13

次のコードを検討します。

#include <memory>
#include <iostream>

using namespace std;

struct MySharedStruct
{
  int i;
};

void print_value_of_i(weak_ptr<MySharedStruct> weakPtr)
{
  if (shared_ptr<MySharedStruct> sp = weakPtr.lock())
  { cout << "Value of i = " << sp->i << endl; }
  else
  { cout << "Resource has expired"; }
}

int main()
{
  shared_ptr<MySharedStruct> sharedPtr(new MySharedStruct() );
  sharedPtr->i = 5;

  weak_ptr<MySharedStruct> weakPtr;
  weakPtr = sharedPtr;

  print_value_of_i(weakPtr);

  sharedPtr.reset(new MySharedStruct() ); // <<----- How does weak_ptr know it has expired after this line executes?
  sharedPtr->i = 10;

  print_value_of_i(weakPtr);

  return 0;
}

参照していたリソースが本質的に別のリソースに置き換えられたweak_ptrことを考慮して、期限切れになったことをどのようにして知ることができますか?古い共有リソースが破棄され、新しい共有リソースに置き換えられたことを確認するために、shared_ptrweak_ptrを追跡しますか?そのような方法の定義例(該当する場合)をいただければ幸いです。lockweak_ptr

4

2 に答える 2

14

プレーンポインタから作成されるときに割り当てられる制御ブロックにshared_ptrは、オブジェクトの参照カウンタと、オブジェクト自体およびカスタム削除オブジェクト(存在する場合)へのポインタの両方が含まれます。その参照カウンターがゼロに達すると、オブジェクトが解放され、ポインターがnullに設定されます。したがって、オブジェクト参照カウンターがゼロの場合、それはオブジェクトがなくなったことを意味します。

x86およびx86-64の場合、これらはアトミック操作を使用し、明示的なロックは使用しません(ミューテックスまたはスピンロックは使用しません)。atomic_conditional_increment実装の秘訣は、オブジェクト参照カウンターがゼロでない場合にのみインクリメントする特別なロックフリー(ビジースピン用のコード言語)関数です。これは、オブジェクト参照カウンターがゼロの状態weak_ptr::lockで複数のスレッドshared_ptrが同じスレッドからを作成しようとする場合の競合に対処するための関数の実装で使用されます。http://www.boost.org/doc/libs/1_52_0/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hppweak_ptrを参照してください

shared_ptr制御ブロック自体は'sと'sの間で共有されweak_ptr、それ自体に別の参照カウンターがあるため、制御ブロックへの最後の参照が解放されるまで存続します。

ashared_ptrが再割り当てされると、それは別の制御ブロックを指すため、制御ブロックは1つの同じオブジェクトのみを指します。つまり、制御ブロック内で1つのオブジェクトを別のオブジェクトに置き換えることはありません。

于 2012-12-26T16:30:53.577 に答える
12

短い答え

ほとんどの実装は、とを参照する共有制御ブロックを持つことでこれを達成していると思いweakPtrますsharedPtr。がリセットされると、ポインタが有効かどうかをテストするために使用できる制御ブロックのsharedPtraがデクリメントされます。use_countweakPtr

長い答え

しかし、それは実装によって異なる可能性があると思います。これは、C++11標準が発生するはずだと言っていることのブローバイブローです。

shared_ptr<MySharedStruct> sharedPtr(new MySharedStruct());

20.7.2.2.1に従ってsharedPtr指定されたデータの所有権で構築されます。

weak_ptr<MySharedStruct> weakPtr;
weakPtr = sharedPtr;

20.7.2.3.1に従ってweakPtrが作成され、値が割り当てられますsharedPtr。割り当て後、指定されたデータの所有権を共有しますweakPtrsharedPtr

sharedPtr.reset(new MySharedStruct());

20.7.2.2.4によると、はとreset(Y*)同等shared_ptr(Y*).swap(*this)です。つまり、その内容を、新しいデータを所有 sharedPtrする一時的なものと交換します。shared_ptr

スワップ後、sharedPtrは新しいデータを所有し、一時的には古いデータの所有権を。と共有しweakPtrます。

20.7.2.2.2に従って、一時的なものは破棄されます。

  • 一時は古いデータを所有し、その所有権を別のインスタンスと共有しないためshared_ptr、古いデータを削除します。
  • 一時的なものと所有権を共有するすべてのインスタンスは、以前の値より1つ少ない値shared_ptrを報告します。use_count()

つまり、weakPtr.use_count() == 0

if (shared_ptr<MySharedStruct> sp = weakPtr.lock()) { 
  cout << "Value of i = " << sp->i << endl;
} else {
  cout << "Resource has expired"; 
}

20.7.2.3.5によると、呼び出しlockは次のようになります。

expired() ? shared_ptr<T>() : shared_ptr<T>(*this)

...そしてexpired()と同等です

use_count() == 0

...これはlock空を返すことを意味しますshared_ptr

于 2012-12-26T17:58:31.207 に答える