2016-09-07 12 views
3

データ型の制限に達すると、データ型のサイズを増やしたいと考えています。たとえば、のは、私はクラスを持っているとしましょう:私はCounter.xの値を変更するとデータ型の制限に達すると、データ型を動的に変更する簡単かつ効率的な方法はありますか?

struct Counter { 
    unsigned short x; 
    void IncrementCount() { x++; } 
}; 

は、私が代わりにunsigned short型のunsigned int型であることをXを促進するためにそれをしたいと思います。

int main() { 
    Counter c; 
    c.x = ~0; // c.x is max unsigned short value 2^16 
    c.IncrementCount();  // c.x is now an unsigned int with value 2^16 + 1, NOT an unsigned short with value 0 
} 

私がこれをやっているのは、可能な限りカウンタークラスに少しのメモリを保存するためです。

明らかに、パフォーマンスと可読性をできるだけ低下させたいと思っています。

voidポインタを使用し、適切なデータ型にキャストすることを検討しましたが(余分なメモリを使用せずに型を追跡する方法は?)、CounterクラスのIncrementCount()メソッドを変更して、 unsigned shortの限界に達すると(短いものではなくintを使用します)(ただし、これによって複雑さが増します。また、増分ごとに余分なifが追加されます)。たぶん、余分なビットが必要なたびにサイズが増加するビットマップですか?複雑さといくつかのパフォーマンスヒットを追加します。

私は1000万のカウンターを持っていますが、私はintに余分な2バイトを使いたくありません(余分な2千万のバイトが必要です)。私はアラインメントがshort - > intの問題を修正する可能性があることを知っていますが、これはint32 - > int64と他の型に対しても有効です。これは実行時の問題であることにも注意してください(コンパイル時のサイズは分かりません)。

これを行うにはC++で簡単な方法がありますか?

+3

代わりにbigintライブラリを見てみてください。 – jaggedSpire

+0

それをテンプレートにして、基礎となるタイプを指定するのはなぜでしょうか?そうすれば、小さなカウンターが必要なことが分かっている場合は、小さなタイプを使用します。大きなカウンターが必要な場合や不明な場合は、より大きなタイプを使用しますか? – NathanOliver

+0

これには動的割り当てが必要です –

答えて

0

C++は静的型付き言語です。すべてのデータ構造には変更できないコンパイル時のサイズがあります。

クラスを持つことができますより多くのメモリを割り当てます。しかし、これはクラス自身の記憶域とは別の割り当てです(そして、コメントに記されているように、それはintよりもずっと多くのメモリがかかります)。特定のC++クラスは単一のサイズしか持たない。

0

2,000万の値のデータストレージポリシーを見てください。

オブジェクトを配列に格納する場合、オブジェクトのサイズとタイプは石で設定されます。それがニコールの答えです。これは、コメントで推奨されているものです:必要な最大の整数型を使用し、実行します。

オブジェクトへのポインタを格納する場合、より大きな値のスペースを持つ別の型を指すオブジェクトを自由に置き換えることができます。しかし、最初にからのメモリオーバーヘッドがに組み込まれています。これはおそらく、値ごとに2つのポインタのオーバーヘッドがあります(2つ目は多相オブジェクト内の隠れたvtableポインタです)。それは意味をなさない。

の基本整数型を変更する場合は、整数を動的に割り当て、オブジェクト内のそのメモリへのポインタを保持する必要があります。同じオーバーヘッドで、ポインタ(今度はさまざまなサイズの整数オブジェクト)をオブジェクトに移動しました。ヒープ管理用のメモリオーバーヘッドは、ここのような小さなチャンクで支配的になります。

1

唯一の方法は、あなたが言ったように、インクリメントされた値が現在の型に適合するかどうかをチェックすることです。そうでない場合、uint16の代わりにuint32と言う新しいobjを作成して古いvalをコピーします。しかし、この場合、オブジェクトが多型であれば、追加の8バイトのメモリを必要とする仮想テーブル関数へのポインタを含まなければなりません。

確かに、基本データ型ではなく、別のデータ構造体にカウント数を格納することを検討できますが、多くのメモリを必要とする追加情報が含まれている可能性がありますオプション。また、ポインターは32-64ビット(マシンによって異なる)であり、uint64を格納するのと同じであるため、フリーストアを扱うことはできません。

これは、ベクトルのメモリを再割り当てするときにコピーしなければならないのと同じ理由をコピーすることを避けることができないということです。メモリのカウンターの隣に何があるのか​​決して今は決してできません - 今度はタイプを単に "サイズ変更する"ようになりました。

現在のタイプではカウンタの数値が大きすぎて新しいタイプが必要であることをどのように把握できますか?非常に単純です。x + 1の値が0に等しいかどうかをチェックしてください。もし起こったならば、オーバーフローが発生しましたか?>現在のタイプは小さくなります。

要約すると、オブジェクトをサイズ変更できるのはコピーだけです。しかし、それを行うことに同意するならば、チェックとコピーのためのコードを書く必要があります。また、インクリメントごとにバリューチェックのオーバーヘッドを避けることはできません。

1

CおよびC++のデータ型は、コンパイル時に完全に定義する必要があります。あなたはintに昇格される短い変数を持つことはできません。

Pythonのようなプログラミング言語は、変数ではなく値にデータ型を添付します。これが理由です。

a = 1 
a = "hi" 

データ型は値1に、値「hi」に割り当てられているためです。

"a"の簿記は通常、動的に割り当てられたメモリブロックへのポインタ、動的メモリ割り当てのための簿記、少なくとも1つのポインタがデータ型判別メカニズムを持っています。データ型の値を取得します。このメカニズムにより、実行時の効率を低下させながら実行時にデータ型を推測することができます。

これを実装するには少なくとも2つの方法があります。歴史的に、これはバリアントデータ型として行われています。 See here for more information。代わりに、すべての可能な操作で基本クラスObjectを持つ、オブジェクト指向の方法としてそれを行うことです。これは多かれ少なかれPythonがやっていることですが、C++では代わりに関数ポインタがあります。例えば:

class Object { 
public: 
    virtual Object_ptr add(Object_ptr other) = 0; 
}; 

例えばint型用+操作は通常の算術が追加され、2 + 2 = 4が、文字列には、連結演算であり、ここで、「ハロー」+「世界」=「Hello World」の。同じロジックに従うことで、次のことができます。

class IntObject { 
public: 
    virtual Object_ptr add(Object_ptr other) { 
    if (other->dataType() == DATATYPE_INT) { 
     return new IntObject(this->value + other->value); 
    } else { 
     raiseError("dataTypeError"); 
    } 
    } 
}; 

Pythonには、任意の長さの整数の優れた機能もあります。あなたは、あなたが持っているメモリと同じくらい多くのビット数を持つことができます。 Pythonでたとえば:

>>> 1<<128 
340282366920938463463374607431768211456L 

内部的には、Pythonは数がINT32/int64型に収まらないと、実行時にデータ型をアップグレードすることを検知します。これは、Pythonが多かれ少なかれ内部で行うことです:

class IntObject { 
public: 
    virtual Object_ptr add(Object_ptr other) { 
    if (other->dataType() == DATATYPE_INT) { 
     if (operationWillOverflow(other)) { 
     auto a = new LongIntObject(this); 
     auto b = new LongIntObject(other); 
     return a.add(b); 
     } else { 
     return new IntObject(this->value + other->value); 
     } 
    } else { 
     raiseError("dataTypeError"); 
    } 
    } 
}; 
+0

countがcountに達すると、別のデータ型(例えば、shortではなくintを持つCounterクラスの正確なコピー)を保持する新しいObjectを返すという考えはどう思いますか?データ型の制限? – Andrew

+0

仮想メソッドを持つクラスのC++インスタンスでは、vtableに少なくとも4/8バイトのペナルティがあります。そして、あなたはインスタンスへのポインタを支払わなければなりません。したがって、2バイトを節約しますが、さらに16バイトを支払う必要があります。また、実行される余分なコードを支払う必要があります。また、仮想メソッド呼び出しは通常10倍遅くなります。 – vz0

+0

しかし、カウンターが既に仮想メソッドで継承の一部だった場合、その罰金は無効になりますか?明らかに私の単純な例と同じユースケースではありませんが、それは注目に値します。 – Andrew

関連する問題