2

オブジェクトへの共有ポインターを返す関数があります (多くの大きな依存関係があるため、MyObject 定義を含めるのは困難です)。

std::shared_ptr<MyObject> f(std::string params)
{
  return std::shared_ptr<MyObject>(new MyObject(params));
}

このコードが機能する理由を知っている人はいますか:

ケース 1: エラーなしvalgrind -v --tool=memcheck

std::shared_ptr<MyObject> obj_ptr = f("hello");
MyObject obj = *obj_ptr;

このコードがクラッシュしている間:

ケース 2: クラッシュし、いくつかのエラーが発生するvalgrind -v --tool=memcheck

MyObject obj = *f("hello");

MyObject クラスには、動作する代入演算子とコピー コンストラクターがあります (どちらもCase 1で検証済み)。

std::shared_ptr<MyObject>また、 (経由で)を作成し、fそれをポインターにコピーし、ポインターをスタック上のオブジェクトにコピーし、ポインターを削除しようとしました。スタック上の最後のオブジェクトは問題ありません。

ケース 3: エラーなしvalgrind -v --tool=memcheck

std::shared_ptr<MyObject> obj_ptr = f("hello");
MyObject * obj_ptr2 = new MyObject(*obj_ptr);
MyObject obj3 = *obj_ptr2;
delete obj_ptr2;
obj3.print();

エラーは、おそらく右辺値として作成され、オペレーターが実行std::shared_ptrされるとすぐにメモリを解放するためですか?*

4

1 に答える 1

8

問題は (ほぼ確実に) のメンバーの 1 つをMyObjectそのコピー コンストラクターで浅いコピーしていることです。次に、有効ではなくなった浅いデータにアクセスしようとするか、二重に削除します。

ケースを考えてみましょう: 1 番目と 3 番目のケースでは、すべてのコピーが作成された最初のオブジェクトは、スタック オブジェクトを操作するときにまだ生きています。2 番目のケースでshared_ptrは、コピーの作成後に が消え、 のデストラクタが呼び出されMyObjectます。

このように 3 番目のケースを変更すると、クラッシュするのではないかと思います。

MyObject * obj_ptr2 = new MyObject("hello");
MyObject obj3 = *obj_ptr2;
delete obj_ptr2;
obj3.print();
于 2012-05-09T22:49:36.073 に答える