std::allocator
を持つ標準コンテナは、size_type
として定義されていstd::size_t
ます。ただし、サイズを a で表すことができないオブジェクトを割り当てるアロケーターを使用することは可能size_t
ですか? 言い換えると、 asize_type
が よりも大きくなることはありsize_t
ますか?
7 に答える
はい、これは場合によっては役立ちます。
仮想メモリに収まらないほど多くのストレージにアクセスしたいプログラムがあるとします。メモリ マップド ストレージを参照するアロケータを作成し、必要に応じてpointer
オブジェクトを間接的にマッピングすることで、大量のメモリに任意にアクセスできます。
これは、任意のオブジェクトのサイズを格納するのに十分な大きさとして定義されているため、18.2:6 に準拠したままですsize_t
が、17.6.3.5:2 テーブル 28 では、割り当てモデル内の最大のオブジェクトsize_type
のサイズを格納すると定義されており、実際のオブジェクトである必要はありません。 C++ メモリ モデルで。
17.6.3.5:2 表 28 の要件は、複数のオブジェクトの割り当てが配列になるという要件を構成するものではないことに注意してください。allocate(n)
要件は次のとおりです。
n
タイプのオブジェクトにメモリが割り当てられますT
deallocate
アサーションは次のとおりです。
が指す領域内のすべての
n
T
オブジェクトは、p
この呼び出しの前に破棄されます。
arrayではなくareaに注意してください。もう 1 つのポイントは 17.6.3.5:4 です。
X::pointer
、、、および型はX::const_pointer
、NullablePointer (17.6.3.3) の要件を満たさなければなりません。これらの型に対するコンストラクター、比較演算子、コピー操作、移動操作、またはスワップ操作は、例外によって終了しません。また、ランダムアクセス反復子 (24.2) の要件も満たさなければなりません。X::void_pointer
X::const_void_pointer
X::pointer
X::const_pointer
(&*p) + n
と同じである必要はありませんp + n
。
別のモデル内で表現可能なモデルが、外部モデルで表現できないオブジェクトを含むことは完全に正当です。たとえば、数学的論理における非標準モデルです。
size_t
を適用して取得する符号なし整数の型ですsizeof
。
sizeof
彼の引数である型(または式の型)のサイズを返す必要があります。配列の場合は、配列全体のサイズを返す必要があります。
これは、次のことを意味します。
表現できるものよりも大きい構造または結合は存在できません
size_t
。表現できるものよりも大きい配列は存在できません
size_t
。
言い換えると、アクセスできる連続メモリの最大ブロックに何かが収まる場合、そのサイズはsize_tに収まる必要があります(ポータブルではありませんが、直感的に理解しやすい用語です。これは、ほとんどのシステムで、可能size_t
な限り大きいことを意味します。void*
仮想アドレス空間全体を「測定」します)。
編集:この次の文はおそらく間違っています。下記参照
したがって、答えは、サイズを?で表すことができないオブジェクトを割り当てるアロケータを持つことが可能です。size_t
いいえです。
編集(補遺):
私はそれについて考えてきました、そして上記は実際には間違っています。標準を確認しましたが、ポインター、constポインター、voidポインター、const voidポインターにさまざまな型を使用するなど、完全にカスタムのポインター型を使用して完全にカスタムのアロケーターを設計できるようです。したがって、アロケータは実際にはsize_tよりも大きいsize_typeを持つことができます。
ただし、これを行うには、完全にカスタムのポインタ型と、対応するアロケータおよびアロケータ特性インスタンスを実際に定義する必要があります。
私が言う理由はsize_type
、アロケータモデルで単一のオブジェクトのサイズまたは複数のオブジェクト(つまり配列)のサイズにまたがる必要があるかどうかがまだ少し不明であるためです。この詳細を調査する必要があります(ただし、今はここでは夕食の時間です:))
Edit2(新しい補遺):
@larsmansとにかく何を受け入れるかを決めたいと思うかもしれません。問題は、直感的に理解できるよりも少し複雑なようです。私の考えは間違いなくコメント以上のものであるため(内容とサイズの両方で)、回答を再度編集しています。
再編集(コメントで指摘されているように、次の2つの段落は正しくありません):
まず第一に、size_type
単なる名前です。もちろん、コンテナを定義size_type
して、好きな意味でコンテナに追加することもできます。あなたsize_type
はフロート、ストリングなど何でもかまいません。
とはいえ、標準ライブラリsize_type
では、コンテナはアクセスを容易にするためにのみコンテナで定義されています。実際にはsize_type
、そのコンテナのアロケータのと同じであると想定されています(そして、size_type
アロケータのは、size_type
そのアロケータのallotator_traitsのである必要があります)。
したがって、今後size_type
、コンテナのは、たとえ定義したものであっても、「慣例により」同じロジックに従うと想定します。@BenVoightは、「@ AnalogFileが説明しているように、割り当てられたメモリはsize_tより大きくすることはできません。したがって、アロケータからsize_typeを継承するコンテナは、size_tよりも大きいsize_typeを持つことはできません。」で答えを始めます。実際、コンテナにsize_type
アロケータからのthenがある場合、それはアロケータから来ると規定しています(彼は継承と言いますが、もちろんそれはクラス継承の常識ではありません)。
size_type
ただし、 (アロケータからのものであっても)aが必然的にに制約されることは100%正しい場合とそうでない場合がありますsize_t
。size_type
問題は、実際には、アロケータ(および対応する特性)がより大きいを定義できるsize_t
かということです。
@BenVoightと@ecatmurはどちらも、バッキングストアがファイルであるユースケースを提案しています。ただし、バッキングストアがコンテンツ専用のファイルであり、そのコンテンツを参照する何かがメモリ内にある場合(これを「ハンドル」と呼びましょう)、実際にはハンドルを含むコンテナを実行しています。ハンドルは、実際のデータをファイルに格納し、そのデータを取得するために必要なものだけをメモリに保持するクラスのインスタンスになりますが、これはコンテナとは無関係です。コンテナはハンドルを格納し、それらはメモリにあり、私たちはまだ「通常の」アドレス空間にいるので、私の最初の応答はまだ有効です。
ただし、別のケースがあります。ハンドルを割り当てているのではなく、実際にファイル(またはデータベース)にデータを格納しており、アロケーター(および相対特性)は、そのバッキングストアを直接管理するポインター、constポインター、voidポインター、constvoidポインターなどのタイプを定義します。もちろん、この場合、一致するように(replaceing)と( size_type
replacing ptrdiff_t)も定義する必要があります。size_t
difference_type
原始積分型が提供する最大の実装と同じくらい大きい場合よりも大きく定義するsize_type
(およびdifference_type
)ことの直接的な困難(そうでない場合は、困難はありません)は、それらが必要であるという事実に関連しています。size_t
size_t
integer types
標準をどのように解釈するかによって、これは不可能(標準に従って、標準integer types
で定義されたタイプと実装によって提供されるタイプであるため)または可能(自分extended integer types
で提供できるように解釈する場合)である可能性があります。プリミティブ型とまったく同じextended integer type
ように動作するクラスを記述できます。これは昔は不可能でした(オーバーロードルールにより、プリミティブ型は常にユーザー定義型と区別できるようになりました)が、私はC ++ 11で100%最新ではなく、これは変更される可能性があります(または変更されない可能性があります)。
ただし、間接的な問題もあります。に適切な整数型を提供する必要があるだけではありませんsize_type
。また、アロケータインターフェイスの残りの部分を提供する必要があります。
私はそれについて少し考えていました、そして私が見る1つの問題は*p
17.6.3.5に従って実装することです。その*p
構文p
ではpointer
、アロケータ特性によって入力されたとおりです。もちろん、クラスを記述してoperator*
(nullaryメソッドバージョン、ポインターの逆参照を行う)を定義することもできます。そして、これはファイルの相対部分を「ページング」することで簡単に実行できると思うかもしれません(@ecatmurが示唆しているように)。ただし、問題があります。そのオブジェクトに*p
はが必要です。T&
したがって、オブジェクト自体がメモリに収まる必要があります。さらに重要なのは、T &ref = *p
そして、その参照を無期限に保持します。データをページインすると、それ以上ページアウトすることはできなくなります。これは、バッキングストア全体をメモリにロードできない限り、このようなアロケータを適切に実装する方法が事実上ない可能性があることを意味します。
これらは私の初期の観察であり、本当の答えはノーであるという私の第一印象を実際に確認しているようです。それを行う実際的な方法はありません。
ただし、ご覧のとおり、単なる直感が示唆するよりもはるかに複雑です。決定的な答えを見つけるのにかなりの時間がかかるかもしれません(そして私は先に進んでトピックをさらに調査するかもしれないし、しないかもしれません)。
今のところ、私はただ言います:それは可能ではないようです。それとは反対のステートメントは、直感だけに基づいていない場合にのみ受け入れられます。コードを投稿し、コードが17.6.3.5に完全に準拠しているかどうか、およびコードが最大のプリミティブと同じくらい大きい場合でも、それsize_type
が大きいかどうかを人々に議論させます。整数型)は整数型と見なすことができます。size_t
size_t
はいといいえ。
@AnalogFile が説明しているように、割り当てられたメモリは より大きくすることはできませんsize_t
。size_type
そのため、アロケーターから継承するコンテナーは、size_type
より大きなサイズを持つことはできませんsize_t
。
ただし、アドレス可能なメモリに完全に格納されていないコレクションを表すコンテナー型を設計できます。たとえば、メンバーはディスク上またはデータベース内にある可能性があります。フィボナッチ数列など、動的に計算することもでき、どこにも保存されません。このような場合、size_type
は簡単に よりも大きくなる可能性がありsize_t
ます。
私はそれが標準のどこかに埋もれていると確信していますが、size_typeについて私が見た最良の説明は SGI-STL ドキュメントからのものです。私が言ったように、私はそれが標準にあると確信しており、誰かがそれを指摘できるなら、ぜひそうしてください.
SGI によると、コンテナの size_type は次のとおりです。
コンテナーの距離型の非負の値を表すことができる符号なし整数型
それ以外のものでなければならないという主張はしません。理論的には、uint64_t、unsigned char、およびその間のその他のものを使用するコンテナーを定義できます。コンテナの distance_type を参照していることは、私が興味深いと思う部分です...
distance_type: コンテナーの 2 つのイテレーター間の距離を表すために使用される符号付き整数型。この型は、反復子の距離型と同じでなければなりません。
ただし、これは質問に対する実際の回答ではありませんが、size_type と size_t がどのように異なるか (または異なる可能性があるか) を確認することは興味深いことです。あなたの質問については、@AnalogFile の回答を参照してください (そして賛成票を投じてください)。
§18.2/6 から
型
size_t
は実装定義の符号なし整数型で、任意のオブジェクトのサイズをバイト単位で格納するのに十分な大きさです。
したがって、a でサイズを表すことができないオブジェクトを割り当てることができた場合size_t
、実装は不適合になります。
「標準」の回答に追加するには、ディスクストレージを使用してテラバイトのデータを処理できると想定されているstxxlプロジェクトにも注意してください(おそらく拡張、ネットワークストレージによる)。uint64 としての(行 731および行 742 )の定義については、たとえばvector のヘッダーを参照してください。size_type
これは、メモリが許容できないサイズ、またはシステムの整数でさえ処理できるサイズよりも大きなサイズのコンテナーを使用する具体的な例です。
必ずしも。
size_type とは、ほとんどの STL コンテナー内の typedef を意味していると思いますか?
もしそうなら、 size_t を使用する代わりに size_type がすべてのコンテナに追加されたという理由だけで、STL が size_type を好きな型にする権利を留保していることを意味します。(デフォルトでは、すべての実装で、size_type が size_t の typedef であることを認識しています)。