web-dev-qa-db-ja.com

C ++ 11はvector <const T>を許可しますか?

コンテナーの要件がC++ 03からC++ 11に変更されました。 C++ 03には包括的な要件(たとえば、ベクターのコピー構築可能性および割り当て可能性)がありましたが、C++ 11には、各コンテナー操作に関する細かい要件が定義されています(セクション23.2)。

その結果、たとえば、割り当てを必要としない特定の操作(構築とPush_backはそのような操作です。 insertはありません)。

私が不思議に思っているのは、これは標準がvector<const T>?理由がわからない-const Tは、constメンバーを持つ構造体と同じように、コピー構築可能で割り当て可能ではない型ですが、何かを見落としている可能性があります。

(私が何かを見逃したかもしれないと私に思わせるものの一部は、インスタンス化しようとするとgccトランクがクラッシュして燃えるということですvector<const T>、ただしvector<T> Tにはconstメンバーがあります)。

73
HighCommander4

いいえ、アロケータの要件では、Tは「非const、非参照オブジェクトタイプ」になる可能性があると言われています。

定数オブジェクトのベクトルでは、多くのことはできません。そして、_const vector<T>_はとにかくほとんど同じです。


何年も経った今でも、この汚い回答はコメントや投票を集めているようです。常に稼働しているわけではありません。 :-)

適切な参照を追加するには:

私が紙に書いているC++ 03標準の場合、セクション[lib.allocator.requirements]の表31は次のように述べています。

_T, U any type_

そのanyタイプが実際に機能したわけではありません。

したがって、次の標準であるC++ 11は、[allocator.requirements]で クローズドラフト と次の表27を示しています。

_T, U, C any non-const, non-reference object type_

これは、私が最初に上記でメモリから書いたものに非常に近いものです。これはまた、質問の内容でもあります。

ただし、C++ 14では( ドラフトN4296 )表27に次のように記載されています。

_T, U, C any non-const object type_

おそらく、参照がおそらくオブジェクト型ではないためでしょうか?

そして今C++ 17( ドラフトN4659 )では、表30で次のように述べています。

T, U, C any cv-unqualified object type (6.9)

したがって、constだけでなく、volatileも除外されます。とにかく古いニュースだと思います。


Howard Hinnantの直接の情報 も参照してください。現在はすぐ下にあります。

41
Bo Persson

更新

受け入れられた(そして正しい)答えの下で、私は2011年にコメントしました:

結論:const Tを保持するコンテナは設計していません。私はそれを少し考えましたが。そして、私たちは偶然にそれを行うことに本当に近づきました。私の知る限り、現在のこだわりは、デフォルトのアロケータのオーバーロードされたaddressメンバー関数のペアです:Tconstの場合、これらの2つのオーバーロードは同じです署名。これを修正する簡単な方法は、std::allocator<const T>を特殊化し、オーバーロードの1つを削除することです。

次のC++ 17ドラフトでは、vector<const T>が合法化されたように見え、偶然にも実行したと思います。 :-)

P0174Raddressオーバーロードをstd::allocator<T>から削除します。 P0174R は、その根拠の一部としてのstd::allocator<const T>のサポートについて言及していません。

修正

以下のコメントでaddressオーバーロードは非推奨であり、削除されないことに注意してください。私の悪い。非推奨のメンバーは、20.10.9ではstd::allocatorが定義されている場所には表示されませんが、代わりにセクションD.9に降格されます。私がこれを投稿したとき、私はこの可能性について第D章をスキャンすることを怠っていました。

T.C.ありがとう修正のため。私はこの誤解を招く答えを削除することを考えましたが、おそらく私が行ったのと同じように他の誰かが仕様を読み違えるのを防ぐために、この修正を残しておくのが最善です。

26
Howard Hinnant

これについては非常に良い答えがすでにありますが、何ができるか、何ができないかを示すために、より実践的な答えを出すことにしました。

したがって、これは機能しません:

vector<const T> vec; 

理由を理解するには、他の回答を読んでください。そして、ご想像のとおり、これも機能しません。

vector<const shared_ptr<T>> vec;

Tconstではなくなりましたが、vectorTsではなくshared_ptrsを保持しています。

一方、これはdoes動作します:

vector<const T *> vec;
vector<T const *> vec;  // the same as above

ただし、この場合、constはポインターが指しているオブジェクトであり、ポインター自体ではありません(ベクターが格納するものです)。これは次と同等です。

vector<shared_ptr<const T>> vec;

結構です。

ただし、式の最後にconstを置くと、ポインターがconstに変わるため、次のコードはコンパイルされません。

vector<T * const> vec;

少しわかりにくいかもしれませんが、あなたはそれに慣れています。

4
Lucio Paiva

他の答えを補完する、別のアプローチは、使用することです:

vector<unique_ptr<const T>> vec;

vecのみがアイテムの所有権を持つことを強制したい場合です。または、アイテムをvecに動的に移動し、ある時点でそれらを外部に移動したい場合。

指摘したように、ポインタconstセマンティクスは混乱するかもしれませんが、shared_ptrおよびunique_ptrではありません。 const unique_ptr<T>はconstポインターであり、unique_ptr<const T>は、予想どおりconst pointeeです。

2
Daniel Gouvêa