std::auto_ptr<>
標準コンテナでの使用が間違っているのはなぜですか?
6 に答える
C++ 標準では、STL 要素は「コピー構築可能」かつ「代入可能」でなければならないと規定しています。つまり、要素は割り当てまたはコピーできる必要があり、2 つの要素は論理的に独立しています。std::auto_ptr
この要件を満たしていません。
たとえば、次のコードを見てください。
class X
{
};
std::vector<std::auto_ptr<X> > vecX;
vecX.push_back(new X);
std::auto_ptr<X> pX = vecX[0]; // vecX[0] is assigned NULL.
この制限を克服するには、 C++ 11 を使用していない場合は、スマート ポインター std::unique_ptr
、std::shared_ptr
または同等のブーストを使用する必要があります。これらのスマート ポインターのブースト ライブラリのドキュメントは次のとおりです。std::weak_ptr
のコピー セマンティクスはauto_ptr
コンテナーと互換性がありません。
具体的には、あるオブジェクトを別のオブジェクトにコピーauto_ptr
しても、一方がポインターの所有権を失っているため、2 つの同等のオブジェクトは作成されません。
より具体的には、をコピーすると、コピーのauto_ptr
1 つがポインターを手放します。これらのうちどれがコンテナに残るかは定義されていません。したがって、auto_ptrs
コンテナーに格納すると、ポインターへのアクセスがランダムに失われる可能性があります。
この件に関する2つの非常に優れた記事:
STL コンテナーは、格納するアイテムをコピーできる必要があり、元のコンテナーとコピーが同等であることを期待するように設計されています。自動ポインター オブジェクトには、完全に異なるコントラクトがあり、コピーすると所有権が譲渡されます。これは、auto_ptr のコンテナーが、使用状況によっては奇妙な動作を示すことを意味します。
何がうまくいかないかについては、Effective STL (Scott Meyers) の項目 8 に詳細な説明があり、Effective C++ (Scott Meyers) の項目 13 にはそれほど詳細ではない説明もあります。
STL コンテナーには、含まれているアイテムのコピーが格納されます。auto_ptr がコピーされると、古い ptr が null に設定されます。多くのコンテナー メソッドは、この動作によって壊れます。
C++03 標準 (ISO-IEC 14882-2003)は、条項 20.4.5 パラグラフ 3 で次のように述べています。
[...] [注: [...] auto_ptr は、標準ライブラリ コンテナー要素の CopyConstructible および Assignable 要件を満たしていないため、auto_ptr を使用して標準ライブラリ コンテナーをインスタンス化すると、未定義の動作が発生します。— エンドノート]
C++11 標準 (ISO-IEC 14882-2011)は、付録 D.10.1 パラグラフ 3 で次のように述べています。
[...] 注: [...] auto_ptr のインスタンスは、MoveConstructible および MoveAssignable の要件を満たしていますが、CopyConstructible および CopyAssignable の要件を満たしていません。— エンドノート]
C++14 標準 (ISO-IEC 14882-2014)は、付録 C.4.2 付属書 D: 互換機能で次のように述べています。
変更: クラス テンプレート auto_ptr、unary_function、および binary_function、関数テンプレート random_shuffle、および関数テンプレート (およびそれらの戻り値の型) ptr_fun、mem_fun、mem_fun_ref、bind1st、および bind2nd は定義されていません。
理由: 新しい機能に取って代わられました。
元の機能への影響: これらのクラス テンプレートと関数テンプレートを使用する有効な C ++ 2014 コードは、この国際標準でコンパイルできない場合があります。