2

このコードを MS Visual Studio 10 で実行しています。

#include <iostream>
#include <memory>
using namespace std;

class A
{
    int i;
public:
    A(int j) : i(j) {}
    ~A() {}
    void fun()
    {
        cout << "A::i = " << i << endl;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    A aObj(12);
    std::shared_ptr<A> const pObj (&aObj,
                [] (A* pA) {
                    cout << "lambda deleter" << endl;
                });
    aObj.~A();
    pObj->fun();
    return 0;
}

これは、すでに削除されているオブジェクトのデータ メンバーを出力/保持しますが、エラーは報告されません。

記入してください:

  1. shared_ptrpObj が (実行時に) 基になるオブジェクトが既に削除されていることを報告しないのはなぜですか?
  2. 私は const shared_ptr を作成しているので、それを使用して他のオブジェクトを参照することはできません。オブジェクトの削除時にラムダが呼び出されないのはなぜですか。
  3. weak_ptr同様のケースで役立ちます。weak_ptrオブジェクトへの参照の存続期間は、参照先のオブジェクトよりも長生きするというセマンティクスで使用されます。
4

1 に答える 1

20

なぜ shared_ptr pObj は (実行時に) 基になるオブジェクトが既に削除されていると報告しないのですか?

魔法shared_ptrじゃないから1 . 含まれているオブジェクトがいつ削除されたかは、そのオブジェクトを削除したときにのみわかります。を利用することで、 との契約を締結したことになります。その契約のテナントの 1 つ (実際、あらゆる種類のスマート ポインターで締結する契約の) は、ポインターを削除できないことです。インスタンスはポインターを所有しており、あなたではなく、それを削除します。shared_ptrshared_ptrshared_ptr

その契約に違反すると、未定義の動作が発生します。

私は const shared_ptr を作成しているので、それを使用して他のオブジェクトを参照することはできません。オブジェクトの削除時にラムダが呼び出されないのはなぜですか。

繰り返しになりshared_ptrますが、 は、含まれているオブジェクトが削除されたことのみを認識できます。コントラクトを破ると、オブジェクトの状態について何もわかりません。

同様のケースでweak_ptrが役立つ可能性があります。weak_ptr は、オブジェクトへの参照の有効期間が、それが参照するオブジェクトよりも長生きするというセマンティクスで使用されます。

weak_ptrよりも魔法的に恵まれているわけではありませんshared_ptr。それが作成されたセットがweak_ptr知っていることだけを知っています。オブジェクトが削除されたことを が認識しないshared_ptr場合、も認識しません。shared_ptrweak_ptr


1「魔法」とは、C++ では不可能なことを行うことを意味します。関数が呼び出されたこと (およびデストラクタが関数呼び出しであること) を知りたい場合、それを行う方法は 2 つしかありません。その関数が呼び出されたことを通知するか (表示可能な値を設定することによって)、または他の関数を呼び出す関数を呼び出すシステムをセットアップします。

最初のシステムでは、呼び出されたことを人々に知らせるために明示的に記述された関数が必要です。古い関数ではそれを行うことはできません。そのために設計する必要があります。2 番目のシステムでは、全員が新しい関数を使用し、古い関数は誰も使用しない必要があります。誰かが古いものを直接使用しても、コードはそれを認識しません。

最初の方法は「侵入型」と呼ばれ (オブジェクトを特別な方法で記述する必要があるため)、それを使用するスマート ポインターは「侵入型スマート ポインター」と呼ばれます。2 番目の方法は非侵入的です (オブジェクトの特別なコードは必要ありません)。shared_ptr、および現在のすべての標準スマート ポインターは非侵入型です。これは、それらを任意のオブジェクトで使用できることを意味しますが、契約を順守する場合にのみ使用できます。

C++ には 3 番目の方法はありません。したがって、何らかの方法でデストラクタ呼び出しに侵入できるクラス、つまり、デストラクタが呼び出されたことを明示的に通知せずに呼び出されたことを認識できるクラスはあり得ません。したがって、魔法になります。

于 2013-04-05T10:08:44.983 に答える