scoped_ptr は、この目的に非常に適しています。しかし、そのセマンティクスを理解する必要があります。次の 2 つの主要なプロパティを使用して、スマート ポインターをグループ化できます。
- コピー可能: スマート ポインターをコピーできます: コピーと元の共有所有権。
- 移動可能: スマート ポインターを移動できます。移動結果は所有権を持ち、元のポインターは所有しなくなります。
それはかなり一般的な用語です。スマート ポインターには、これらのプロパティをより適切に示す特定の用語があります。
- 所有権の譲渡: スマート ポインターは可動です
- 所有権の共有: スマート ポインターはコピー可能です。スマート ポインターが既にコピー可能である場合、所有権の譲渡セマンティックをサポートするのは簡単です。これは、特定の種類のスマート ポインター (たとえば、一時的なスマート ポインターのみ) に制限する、単なるアトミックコピーおよび元のリセット操作です。
(C)opyable
、 、(M)ovable
、を使用して、利用可能なスマート ポインターをグループ化しましょう(N)either
。
boost::scoped_ptr
:いいえ
std::auto_ptr
:M
boost::shared_ptr
:C
auto_ptr
には、コピー コンストラクターを使用して Moverable の概念を実現するという点で、1 つの大きな問題があります。これは、auto_ptr が C++ に受け入れられたとき、新しい C++ 標準とは対照的に、移動コンストラクターを使用して移動セマンティクスをネイティブにサポートする方法がまだなかったためです。つまり、auto_ptr を使用して次のことができ、それが機能します。
auto_ptr<int> a(new int), b;
// oops, after this, a is reset. But a copy was desired!
// it does the copy&reset-of-original, but it's not restricted to only temporary
// auto_ptrs (so, not to ones that are returned from functions, for example).
b = a;
とにかく、ご覧のとおり、あなたの場合、所有権を別のオブジェクトに譲渡することはできません。あなたのオブジェクトは事実上コピー不可になります。そして、次の C++ 標準では、scoped_ptr のままだと移動不可になります。
scoped_ptr を使用してクラスを実装するには、次の 2 つの点のいずれかが満たされていることを確認してください。
- クラスの .cpp ファイルにデストラクタを (空であっても) 記述します。または
- 完全
Owned
に定義されたクラスを作成します。
それ以外の場合、Example のオブジェクトを作成すると、コンパイラは暗黙的にデストラクタを定義し、scoped_ptr のデストラクタを呼び出します。
~Example() { ptr.~scoped_ptr<Owned>(); }
それから scoped_ptr callが行われ、上記の 2 つの点のいずれも行っていない場合、不完全でboost::checked_delete
あると文句を言います。Owned
.cpp ファイルで独自の dtor を定義した場合、scoped_ptr のデストラクタへの暗黙的な呼び出しは、Owned
クラスの定義を配置できる .cpp ファイルから行われます。
auto_ptr にも同じ問題がありますが、もう 1 つ問題があります。auto_ptr に不完全な型を指定すると、現在未定義の動作です (次の C++ バージョンで修正される可能性があります)。したがって、auto_ptr を使用する場合は、ヘッダー ファイル内で Owned を完全な型にする必要があります。
shared_ptr には、delete を間接的に呼び出すポリモーフィックな削除機能が使用されているため、この問題はありません。したがって、削除関数は、デストラクタがインスタンス化された時点ではインスタンス化されませんが、shared_ptr のコンストラクタでデリータが作成された時点でインスタンス化されます。