6

shared_ptr が含まれているのと同じアドレスにリセットされたときに、weak_ptr が期限切れになることが保証されていますか?

#include <cassert>
#include <memory>

int main()
{
    int* i = new int(0);
    std::shared_ptr<int> si( i );
    std::weak_ptr<int> wi = si;

    si.reset( i );

    assert( wi.expired() ); // wi.expired() == true (GCC 4.7)
}

または、これは の値がwi.expired()定義されていない場合に当てはまりますか?

編集:

質問を少し変更します。

が初期化されたときに含まれていた同じアドレスにリセットされたweak_ptrときに期限切れになることが保証されていますか?shared_ptrshared_ptrweak_ptr

#include <cassert>
#include <memory>

int main()
{
    int* i = new int(0);
    std::shared_ptr<int> si( i );
    std::weak_ptr<int> wi = si;

    si.reset();

    int* j = new int(0); 
    // Suppose that new returns the same address that contains variable i :  
    assert(j == i); 

    si.reset( j );

    assert( wi.expired() ); // wi.expired() == true (GCC 4.7)
}
4

1 に答える 1

11

一方では、実際にはそうすべきです。一方、同じポインターを 2 つの異なる共有ポインター (si-before-reset と si-after-reset) に割り当てることは正しくありません。実際、それを呼び出すと、次のsi.reset(i)ことが起こります。

  • si0 へのドロップの参照カウント
  • delete i呼び出される
  • 生まれ変わった人は再びsi指しiます。

iそのため、リセット後に新しく割り当てられたメモリは、割り当てられていないメモリを指し、正しく期限切れになります (そして、最後に再度削除しようとするとwi、segfault が発生します)。sii

shared_ptr に割り当てられた後は、ネイキッド ポインターを参照しないことをお勧めします。

編集後の回答:

そこにも同じことが当てはまります。ポインターが同じであるという事実は、shared_ptr とその内部参照カウントとは何の関係もありません。これは、「悪」の例でより明確になる可能性があります。これは間違っています:

  int *i = new int;

  std::shared_ptr<int> si1(i);
  std::shared_ptr<int> si2(i); // deleting twice i on destruction of si2 - boom!
  std::weak_ptr<int> wi1 = si1;

  si1.reset();
  assert (wi1.expired());      // true

これは最初の例と似ています (実際には同じです)。si1andが (誤って) 同じメモリを指しているという事実si2は、shared_ptr および接続された weak_ptr の寿命とは何の関係もありません。

iポインターの絶対値は、ref-count の決定には使用されません。shared_ptr と weak_ptr の両方。そうです、それは保証されています!

実際、クラス内からオブジェクトの shared_ptr が必要な場合は、enable_shared_from_thisが必要です - shared_from_this()shared_ptr(this)の代わりに使用していた場合、毎回異なる shared_ptr を取得していました - それらの最初のものが出るとすぐにオブジェクトを破棄します参照カウントの。

于 2014-07-17T13:40:01.023 に答える