私は読んでいます http://gcc.gnu.org/onlinedocs/libstdc++/manual/shared_ptr.html といくつかのスレッドの安全性の問題はまだ明確ではありません:
編集:
擬似コード:
// Thread I
shared_ptr<A> a (new A (1));
// Thread II
shared_ptr<A> b (a);
// Thread III
shared_ptr<A> c (a);
// Thread IV
shared_ptr<A> d (a);
d.reset (new A (10));
スレッドIVでreset()を呼び出すと、最初のスレッドで作成されたAクラスの以前のインスタンスが削除され、新しいインスタンスに置き換えられますか?さらに、IVスレッドでreset()を呼び出した後、他のスレッドは新しく作成されたオブジェクトのみを参照しますか?
他の人が指摘したように、あなたはあなたの元の3つの質問に関してそれを正しく理解しました。
しかし、編集の最後の部分
スレッドIVでreset()を呼び出すと、最初のスレッドで作成されたAクラスの以前のインスタンスが削除され、新しいインスタンスに置き換えられますか?さらに、IVスレッドでreset()を呼び出した後、他のスレッドは新しく作成されたオブジェクトのみを参照しますか?
間違っています。 d
のみが新しいA(10)
をポイントし、a
、b
、およびc
は元のA(1)
。これは、次の短い例で明確に見ることができます。
#include <memory>
#include <iostream>
using namespace std;
struct A
{
int a;
A(int a) : a(a) {}
};
int main(int argc, char **argv)
{
shared_ptr<A> a(new A(1));
shared_ptr<A> b(a), c(a), d(a);
cout << "a: " << a->a << "\tb: " << b->a
<< "\tc: " << c->a << "\td: " << d->a << endl;
d.reset(new A(10));
cout << "a: " << a->a << "\tb: " << b->a
<< "\tc: " << c->a << "\td: " << d->a << endl;
return 0;
}
(明らかに、私はスレッド化を気にしませんでした:それはshared_ptr::reset()
動作を考慮しません。)
このコードの出力は
a:1 b:1 c:1 d:1
a:1 b:1 c:1 d:10
正解、shared_ptr
sは、参照カウント値のアトミックなインクリメント/デクリメントを使用します。
標準では、共有オブジェクトに対して1つのスレッドのみが削除演算子を呼び出すことを保証しています。共有ポインターのコピーを削除する最後のスレッドがdeleteを呼び出すスレッドになることを明確に指定しているかどうかはわかりません(実際には、これが事実です)。
いいえ、保存されているオブジェクトは複数のスレッドで同時に編集できます。
編集:わずかなフォローアップ。共有ポインターが一般的にどのように機能するかを知りたい場合は、boost::shared_ptr
ソース: http://www.boost.org/doc/libs/1_37_0/boost/shared_ptr.hpp 。
std::shared_ptr
はスレッドセーフではありません。
共有ポインタは、オブジェクトへのポインタと制御ブロックへのポインタの2つのポインタのペアです(参照カウンタを保持し、弱いポインタへのリンクを...)。
複数のstd :: shared_ptrが存在する可能性があり、制御ブロックにアクセスして参照カウンターを変更する場合は常にスレッドセーフですが、std::shared_ptr
自体はスレッドセーフでもアトミックでもありません。
別のスレッドが使用しているときにstd::shared_ptr
に新しいオブジェクトを割り当てると、新しいオブジェクトポインターで終わる可能性がありますが、それでも古いオブジェクトの制御ブロックへのポインター=> CRASHを使用します。