0

デストラクタを呼び出すこれら 3 つのアプローチに重大な/深刻な違いがあるかどうか知りたいだけです。次のコードを検討してください。で述べた 2 つのケースも考慮してくださいmain()

class Sample 
{
public:
    ~Sample()
    {
        cout << "destructor called" << endl;
    }
    void destroyApproach1() { this->~Sample(); }
    void destroyApproach2() { delete this; }
};

void destroyApproach3(Sample *_this)
{
    delete _this;
}

void TestUsingNew()
{
    Sample *pSample[] = { new Sample(), new Sample(),new Sample()};
    pSample[0]->destroyApproach1();
    pSample[1]->destroyApproach2();
    destroyApproach3(pSample[2]);
}
void TestUsingPlacementNew()
{
    void *buf1 = std::malloc(sizeof(Sample));
    void *buf2 = std::malloc(sizeof(Sample));
    void *buf3 = std::malloc(sizeof(Sample));
    Sample *pSample[3] = { new (buf1) Sample(), new (buf2) Sample(), new (buf3) Sample()};
    pSample[0]->destroyApproach1();
    pSample[1]->destroyApproach2();
    destroyApproach3(pSample[2]);
}
int main() 
{ 
    //Case 1 : when using new
    TestUsingNew();

    //Case 2 : when using placement new
    TestUsingPlacementNew();
    return 0;
}

返信する際は、ケース 1 またはケース 2、またはその両方のケースについて具体的にお答えください


また、このように書こうとしたTestUsingPlacementNew()のですが、実行時例外(MSVC++2008)を投げています。理由がわかりません:

void TestUsingPlacementNew()
{
    const int size = sizeof(Sample);
    char *buffer = (char*)std::malloc( size * 3);
    Sample *pSample[] = { new (buffer) Sample(), new (&buffer[size]) Sample(),new  (&buffer[2*size]) Sample()};
    pSample[0]->destroyApproach1();
    pSample[1]->destroyApproach2();
    destroyApproach3(pSample[2]);
}

おそらく、メモリのパディングやアライメントが原因でしょうか?


関連トピック :オブジェクトの配置を破棄した後にデストラクタが呼び出されない - 新規作成

4

2 に答える 2

5

はい、これらのアプローチには大きな違いがあります。

  • ではdestroyApproach1、オブジェクトのデストラクタのみを呼び出します。占有していたメモリを実際に解放することはありません。

  • destroyApproach2destroyApproach3オブジェクトのデストラクタを呼び出し、オブジェクトが占有していたメモリを解放します(式を使用してdelete。最初のテストでは、オブジェクトが占有するメモリが最初は。ではなくTestUsingPlacementNewへの呼び出しによって割り当てられたため、これらの両方も間違っています。mallocnew

最後のテストのランタイムエラーは、配列のdeleteインデックスにあるオブジェクトを試行したために発生します。1その要素へのポインタは、最初はへの呼び出しから取得されませんでしたnew。最初の例では、3つのポインターすべてが独立したヒープ割り当てを指しているため、「機能する」(「機能する」は実際には「動作は定義されていませんが、正しく機能しているように見えます」を意味します)のみです。

于 2010-12-13T06:27:33.537 に答える
1

delete this現代のコードでデストラクタを呼び出す正しい方法ではありません。一般に、デストラクタを呼び出す必要はありません。デストラクタの魔法は、適切なタイミングで呼び出されることです。

struct A {
    ~A() { std::cout << "running destructor\n"; }
};

int main()
{
    A a;
    return 0;
}

deleteいずれの場合も、によって割り当てられたメモリを解放するためのものnewです。 delete thisオブジェクトがによって割り当てられなかった場合、問題が発生しますnew

struct B {
    ~B() { delete this }
};

int main()
{
    B b;
    return 0;
}

これにより、実際のオペレーティング システムを備えたほぼすべてのプラットフォームでプログラムがクラッシュします (これは技術的に未定義の動作であり、標準に準拠したプログラムは、この場合、それ自体を破損して実行し続けることが許可されているため、「ほぼすべて」です。プラットフォームに注意してください。破損したメモリ管理データ構造や無効なスタックと一緒に足を引っ張る以上のことを行います)。


配置newは主に、ハードウェア デバイス ドライバーや、ポインターを特別なアドレスに割り当てる必要があるその他の場所を対象としています。 一般に、placement で割り当てられたオブジェクトを破棄したくないでしょうnew。必要に応じて、デストラクタを直接呼び出すだけです。

My_object* o = new(0xffff) My_object();
o->~My_object();

しかし、覚えておいてください、Bjarne Stroustrup は次のように述べています。そう」(C++プログラミング言語、10.4.11)。

于 2010-12-13T07:39:20.323 に答える