2

std::vector膨大な数の要素を32ビットで(unsignedintで許可されている2^ 32-1以上)に格納する必要があります。私の知る限り、この量はstd::size_tunsignedint型によって制限されています。std::size_tにキャストしてこれを変更してもunsigned longいいですか?問題は解決しますか?

それが不可能な場合は、64ビットでコンパイルするとします。それは変更なしで問題を解決しますか?

4

3 に答える 3

6

size_tは、割り当て可能なメモリチャンクのサイズを保持できるタイプです。したがって、自分に収まる以上のメモリを割り当てることはできずsize_t、したがって、どのような方法でもより多くの要素を格納することはできません。

64ビットでコンパイルすると可能になりますが、配列がメモリに収まる必要があることに注意してください。2 32は40億なので、4 * sizeof(element)GiBのメモリを超えることになります。8 GiBを超えるRAMはまだまれであるため、妥当とは思えません。

ベクトルをSTXXLのものに置き換えることをお勧めします。外部ストレージを使用するため、ベクターはRAMの量によって制限されません。ライブラリは、テラバイトのデータを簡単に処理できると主張しています。

(編集)衒学的な注意:size_t最大の単一オブジェクトのサイズを保持する必要がありますが、必ずしもすべての使用可能なメモリのサイズである必要はありません。セグメント化されたメモリモデルでは、各オブジェクトが単一のセグメントに存在する必要がある場合にのみオフセットに対応する必要がありますが、セグメントが異なると、より多くのメモリにアクセスできる場合があります。「長い」メモリモデルであるPAEを使用してx86で使用することも可能です。しかし、実際に使っている人は見たことがありません。

于 2012-06-22T07:21:59.223 に答える
3

言うべきことがたくさんあります。

まず、32ビットシステムと64ビットシステムのそれぞれのサイズについてです。std::size_tこれは、規格が述べていることですstd::size_t(§18.2/ 6,7):

6型size_tは、実装で定義された符号なし整数型であり、任意のオブジェクトのバイト単位のサイズを含めるのに十分な大きさです。

7 [注:すべての可能な値を含めるためにより大きなサイズが必要な場合を除いて、実装では整数変換ランク(4.13)がそれ以下のタイプptrdiff_tを選択することをお勧めします。—エンドノート]size_tsigned long int

このことから、32ビットシステムでstd::size_t少なくとも32ビット、64ビットシステムでは少なくとも64ビットのサイズになります。それはもっと大きくなる可能性がありますが、それは明らかに意味がありません。

第二に、型キャストのアイデアについて:これが機能するためには、理論的にも、それが発生する場所に関係なく、それ自体の実装内で型をキャストする(またはむしろ再定義する)必要があります。std::vector

第三に、「32ビットの」この超大型ベクトルが必要だと言うとき、それは32ビットシステムでそれを使用したいという意味ですか?その場合、他の人がすでに指摘しているように、32ビットシステムにはそれほど多くのメモリがないため、必要なことは不可能です。

しかし、第4に、64ビットマシンでプログラムを実行し、要素のを参照するために32ビットデータ型のみを使用する場合、合計サイズを参照するために64ビット型を使用する場合もあります。バイト単位の場合、std::size_t要素の総数と個々の要素のインデックスを参照するために使用されますが、バイト単位のサイズは参照されないため、関係ありません。

最後に、64ビットシステムを使用していて、のように機能する極端な比率のものを使用したい場合std::vector、それは確かに可能です。32 GB、64 GB、または1 TBのメインメモリを備えたシステムは、おそらくそれほど一般的ではありませんが、確実に利用できます。

ただし、このようなデータ型を実装するには、次のような理由から、1つの連続したブロックにギガバイトのメモリを単純に割り当てることは一般的にお勧めできません(これが実行されます)。std::vector

  • ベクトルの合計サイズが初期化時に一度だけ決定されない限り、ベクトルのサイズが変更され、要素を追加するときに何度も再割り当てされる可能性があります。非常に大きなベクトルの再割り当ては、時間のかかる操作になる可能性があります。[このアイテムを元の回答の編集として追加しました。]
  • 並列で実行されている他のプロセスもメモリを必要とするため、OSは断片化されていないメモリのこのような大部分を提供するのが困難になります。[編集:コメントで正しく指摘されているように、これは現在使用されている標準OSでは実際には問題ではありません。]
  • 非常に大規模なサーバーでは、数十のCPUと通常はNUMAタイプのメモリアーキテクチャもあり、比較的小さなメモリチャンクで作業し、複数のスレッド(それぞれが異なるコアで実行されている可能性があります)がさまざまなチャンクにアクセスすることが明らかに望ましいです。並列のベクトル。

結論

A) 32ビットシステムを使用していて、これほど大きなベクトルを使用したい場合は、@JanHudecによって提案されたようなディスクベースの方法を使用することが実行可能な唯一の方法です。

B)数十または数百GBの大規模な64ビットシステムにアクセスできる場合は、メモリ領域全体をチャンクに分割する実装を検討する必要があります。基本的に、のように機能するものでstd::vector<std::vector<T>>、ネストされた各ベクトルは1つのチャンクを表します。すべてのチャンクがいっぱいの場合は、新しいチャンクなどを追加します。これにもイテレータタイプを実装するのは簡単です。もちろん、これをさらに最適化してマルチスレッドとNUMA機能を利用したい場合は、ますます複雑になりますが、それは避けられません。

于 2012-06-22T08:12:05.160 に答える
0

Avectorはあなたにとって間違ったデータ構造かもしれません。のサイズによって制限されるメモリの単一ブロックにストレージが必要ですsize_t。これは、64ビットシステム用にコンパイルすることで増やすことができますが、32ビットシステムで実行することはできません。これは要件となる可能性があります。

vectorの特定の特性(特にO(1)ルックアップと連続メモリレイアウト)が必要ない場合は、などの別の構造std::listが適している可能性があります。これは、リンクリストであるため、コンピュータが物理的に処理できるものを除いてサイズ制限がありません。便利にラップされたアレイの。

于 2012-06-22T07:26:07.620 に答える