web-dev-qa-db-ja.com

デストラクタを明示的に呼び出す

ほとんどの場合、デストラクタを明示的に呼び出すべきではないことを理解しています。ただし、C++ 11標準N3485セクション13.4.5テンプレート引数の例を参照しました。

クラステンプレートの特殊化である型を持つオブジェクトの明示的なデストラクタ呼び出しは、テンプレート引数を明示的に指定できます。例:

template<class T> struct A {
    ~A();
}; 

void f(A<int>* p, A<int>* q) {
    p->A<int>::~A();      // OK: destructor call
    q->A<int>::~A<int>(); // OK: destructor call
}

この場合、デストラクタを明示的に呼び出すことができるようですが、その理由を教えてください。この例では、これらのデストラクタの呼び出しは何を意味しますか?なぜ彼らは合理的ですか?

別の質問:

placement deleteを実装しているとき以外に、デストラクタを明示的に呼び出すことができるケースは何ですか?

ありがとうございました。

EDIT:C++ FAQ から、ローカル変数のデストラクタを明示的に呼び出すべきではないことがわかりました。

44
taocp

この場合、デストラクタを明示的に呼び出すことができるようですが、その理由を教えてください。

なぜできるのか?言語では、任意のオブジェクトに対する明示的なデストラクター呼び出しが許可されているためです。あなたが言うように、ほとんどのオブジェクトは他の方法で破棄されるため、通常は未定義の動作を提供します。しかし、それは単にあなたがそれをしてはいけないということを意味し、言語があなたがそれをすることを妨げるということではありません。

それとも、なぜ私たちがしたいのですか?それは、新しい配置によって作成されたオブジェクトを破壊する方法だからです。

この例では、これらのデストラクタの呼び出しは何を意味しますか?

これらは両方とも同じことを意味し、p->~A();と同等です。オブジェクトのデストラクタを呼び出します。この例は、必要に応じてテンプレート引数をここで提供できることを示しています。なぜあなたがしたいのか分かりません。

配置の削除以外にデストラクタを明示的に呼び出すことができるケースは何ですか?

I 思考いつでも好きなときに些細なデストラクタ(何もしないデストラクタ)を呼び出すことができます。しかし、意味はありません。新しい配置で作成されたものを破壊することが、それを行う唯一の正当な理由だと思います。

31
Mike Seymour

この場合、デストラクタを明示的に呼び出すことができると思われますが、その理由を説明していただけますか?

言語によって、必要なときにいつでもオブジェクトのデストラクタを呼び出すことが許可されているためです(たとえば、プライベートデストラクタではないアクセス権がある場合)。

この例では、これらのデストラクタ呼び出しは何を意味しますか?

デストラクタを呼び出すだけです。論理的には、オブジェクトが破棄され、その時点からガベージであると見なされるべきであり、逆参照または使用されるべきではないことを意味します。技術的には、オブジェクトはデストラクタが残したままの状態にあることを意味します。一部のオブジェクトについては、mayはデフォルトの構造と同じです(ただし、絶対に依存しないでください)。

なぜ彼らは合理的ですか?

メモリを解放せずにオブジェクトを破棄する必要がある場合があります。これは、variant/any、さまざまなスクリプトバインディングおよびリフレクションシステム、シングルトン実装などの多くのクラスで発生します。

たとえば、_std::aligned_storage_を使用してオブジェクトにバッファを割り当て、次に配置newを使用してそのバッファにオブジェクトを構築できます。このオブジェクトでdeleteを呼び出すことはできません。これは、デストラクタを呼び出し、それをサポートしているメモリを解放しようとするためです。 mustこの場合、明示的にデストラクタを呼び出して、オブジェクトを適切に破壊します。

配置削除のほかにデストラクタを明示的に呼び出すことができるケースは何ですか?

配置newに対応する演算子以外に、実際には「配置削除」というものはありません(そして、deleteへの呼び出しは、コンパイラが失敗した構築のために呼び出すものを除き、デストラクタを暗黙的に呼び出します。 '概念)。

上記の1つの例。別の例は_std::vector_です。 pop_back()のようなメンバー関数を呼び出すことができます。これはベクターの最後の要素を破棄する必要がありますが、オブジェクトを支えるメモリは個別に管理する必要がある大きなバッファの一部であるため、deleteは使用できません。同じことは、オープンアドレス指定ハッシュテーブル、dequeなど、他の多くのコンテナにも当てはまります。これは、デストラクタを明示的に呼び出すために_template typename_を使用する場所の例です。

ライブラリのユーザーが必要とすることはほとんどありませんが、STLや一部のアプリケーションフレームワークなどの低レベルライブラリの実装者は、あちこちで使用する必要がある機能です。

25