30

OK、最初に関連する可能性のあるいくつかのこと:

Clang 3.1 コンパイラを C++11 モードで使用し、標準ライブラリを libc++ に設定しています。

私は C++11 に慣れようとしていますが、そうしているうちに奇妙な動作に出くわしました。それはClangまたはlibc ++の癖かもしれませんが、私はC ++標準語を話すことができず、C ++ 11をサポートする他のコンパイラにアクセスできないため、実際に確認することはできません。インターネットとスタックオーバーフローを検索しました関連するものを見つけることなく、私の能力を最大限に発揮します...だからここに行きます:

shared_ptr / unique_ptr を使用して単純なリソースの RAII を実装する場合、削除時の null ポインターに関してそれらの動作が異なるようです。通常、ヌル ポインターを削除する必要はないことは認識していますが、少なくとも 2 つの STL スマート ポインター間で動作が一致することを期待していました。

特定のケースでは、次のコードを検討してください。

{
    auto Deleter = [](void *){cout << "It's later!" << endl;};
    shared_ptr<void> spDoSomethingLater(nullptr, Deleter);
    unique_ptr<void, void (*)(void *)> upDoSomethingLater(nullptr, Deleter);
    cout << "It's now!" << endl;
}

これから、次のいずれかの出力が期待されます。

a) ポインターがヌルであっても、両方のデリータが呼び出された場合:

"It's now!"
"It's later!"
"It's later!"

b) ポインターが null であるため、どちらのデリータも呼び出されない場合:

"It's now!"

しかし、私はこれらのケースのどちらも観察しません。代わりに、私は次のことを観察します。

"It's now!"
"It's later!"

これは、一方のデリータが呼び出され、もう一方が呼び出されていないことを意味します。さらに調べてみると、shared_ptr のデリータは null 値を保持しているかどうかに関係なく呼び出されますが、unique_ptr のデリータは null 値を保持していない場合にのみ呼び出されることがわかりました。

私の質問: これは実際に標準で指定されている正しい動作ですか? もしそうなら、なぜこのように 2 つの STL タイプ間で指定された動作が異なるのでしょうか? そうでない場合、これは libc++ に報告すべきバグですか?

4

2 に答える 2

28

観察された動作は標準に準拠しています。

についてunique_ptrは、20.7.1.2.2 / 2(デストラクタ効果)は言う

効果:効果get() == nullptrがない場合。それ以外の場合 get_deleter()(get())

の場合shared_ptr、20.7.2.2.2 / 1は、nullポインターをラップしている場合でも、deleterを呼び出す必要があることを示しています。

効果:

  • shared_ptr* thisが空であるか、別のインスタンス( )と所有権を共有している 場合use_count() > 1、副作用はありません。
  • それ以外の場合、* thisがオブジェクトpと削除機能を所有している場合はdd(p)が呼び出されます。
  • それ以外の場合、*これはポインタpを所有し、delete p呼び出されます。

ここで重要な詳細は、「オブジェクトを所有している」という表現pです。20.7.2.2/1は、「オブジェクトがポインタを所有していない場合、shared_ptrオブジェクトは空です」と述べています。20.7.2.2.1/9(関連するコンストラクター)は、「オブジェクトと削除機能を所有するオブジェクトを構築する」と述べています。shared_ptrpd

私が知る限り、その呼び出しは技術的にはshared_ptr 独自のnullポインターを作成し、その結果、削除機能が呼び出されます。これを、shared_ptr」を残すと言われているパラメーターなしのコンストラクターと比較してください。

于 2012-06-22T21:37:28.033 に答える
10

はい、正しい動作です。

§20.7.1.2.2[unique.ptr.single.dtor]/2:

unique_ptrデストラクタ

効果:効果get() == nullptrがない場合。そうでなければget_deleter()(get())

§20.7.2.2.2[util.smartptr.shared.dest]/1:

shared_ptrデストラクタ

効果:

  • *thisshared_ptrであるか、別のインスタンス ( )と所有権を共有している場合use_count() > 1、副作用はありません。
  • それ以外の場合、がオブジェクトを*this 所有しpdeleterが呼び出される場合。dd(p)
  • それ以外の場合は、ポインターを*this 所有しp、deletepが呼び出されます。

shared_ptr が空なので、効果はないのでしょうか? ポインタが null であっても、a ポインタを指定すると shared_ptr空にならないためです。

§20.7.2.2.1[util.smartptr.shared.const]/8–10

shared_ptrコンストラクタ

template<class Y, class D> shared_ptr(Y* p, D d);
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template <class D> shared_ptr(nullptr_t p, D d);
template <class D, class A> shared_ptr(nullptr_t p, D d, A a);

必須: pに変換可能でなければなりませんT*。…</p>

効果: objectと deleterを所有shared_ptrするオブジェクトを構築します。pd

事後条件: use_count() == 1 && get() == p .

これは、shared_ptrがnullptrを所有していることを意味します。したがって、shared_ptr が破棄されると、deleter が呼び出されます。

于 2012-06-22T21:41:14.697 に答える