1

これが私がやっていることです:

#include <iostream>

using namespace std;

class Test
{
public:
    int i;
    Test();
    Test(int x);
    ~Test();

    static void operator delete(void * t);
};

Test::Test() : i(1) { cout << "constructing" << endl; }

Test::Test(int x) : i(x) { cout << "constructing w/ arg" << endl; }

Test::~Test() { cout << "destructing" << endl; }

Test::operator delete(void *self)
{
    cout << "deleting" << endl;
    ((Test *) t)->~Test(); // call destructor since it isnt called otherwise
    ::delete(t); // actually delete memory
}

template <typename T> // too lazy to figure out correct type
void callback(Test *t, T fn)
{
    (fn)(t); // delete operator is implicitly static so this syntax is correct
}

int main()
{
    Test *t = new Test();
    callback(t, &Test::operator delete); // deletes t
}

operator deleteクラスで がオーバーロードされていない限り、前のスニペットはコンパイルに失敗することに気付きました。含まれている場合は、コンパイルして期待どおりに動作します (最初にコンストラクターが呼び出され、次にオーバーロードされた削除、次にデストラクタがそれぞれ 1 回だけ呼び出されます)。

グローバルな delete operator を渡すことを考えまし::operator deleteたが、それも機能しません (未解決のオーバーロードされた関数呼び出しが発生します)。アドレスをうまく取得しようとせずに呼び出すことができます。

の独自のオーバーロードを定義しなくても、私がやっていることは可能::operator deleteですか?

基本的に、このようなものを使用する必要があるユースケースはありません。::operator deleteそれは一般的な使用法ではなく、デストラクタを呼び出さないことを私は知っています....

4

1 に答える 1

4

グローバル演算子new/deleteはオーバーロードされた関数です - 正しい関数ポインタ型にキャストする必要があります:

callback(t, static_cast<void(*)(void*)>(::operator delete));

編集:いくつかのことを明確にするために回答を拡大しています。

デストラクタが global によって呼び出されないことは事実ですoperator delete。メモリをランタイムに戻すのは、割り当て解除関数にすぎません。デストラクタの呼び出しは、式の削除の仕事です:

Delete 式は、最初にオブジェクト (または、配列形式を使用する場合はオブジェクト) のデストラクタを呼び出し、そのポインター引数が指し示す、次に割り当て解除関数を呼び出します (削除されるポインターがクラス型の場合、そのスコープ内でそれを探します)。クラスを最初に呼び出し、見つからない場合はグローバル クラスを呼び出します)。

注意すべきもう 1 つの重要な点はvoid*、削除式でポインターを使用することは未定義の動作であるということです。これは、オーバーロードで行うことです。

cout << "deleting" << endl;
((Test *) self)->~Test();
::delete(self); // this is delete expression using void*, UB

global を呼び出していないoperator deleteため、 と言う必要があります::operator delete(t);。削除式があり、スコープ解決演算子は、解放関数のクラススコープ内を調べないように指示するだけです。

これに変更すると、再度 UB が 2 回印刷される::delete( (Test*) self);ことがわかります。destructing

全体として、内部でデストラクタを呼び出さないでくださいoperator delete。それはその仕事ではありません。

于 2013-07-09T21:50:48.093 に答える