开发者

Invoking Destructor Approach Comparison

I'm just curious to know if there is any significant/serious difference in these three approaches of invoking destructor. Consider the following code. Please also consider the two cases mentioned in 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;
}

Please be specific when replying as to which case you're answering to : case 1 or case 2, or both!


Also, I was trying to write TestUsingPlacementNew() in this way, but it's throwing runtime exception (MSVC++2008). I don't understand why:

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]);
}

Maybe, memory padding and/or alignment could be the reason?


Related topic : Destructor not called after destroying object placement-new'ed


Yes, there is a huge difference between these approaches:

  • In destroyApproach1, you only call the destructor of the object; you don't actually free the memory that it occupied.

  • In destroyApproach2 and destroyApproach3 you call the destructor of the object and you free the memory that the object occupied (by using the delete expression). In the first TestUsingPlacementNew test, both of these are also wrong since the memory occupied by the object was initially allocated by a call to malloc, not by new.

The runtime error in your last test occurs because you attempt to delete the object at index 1 in the array; the pointer to that element was not initially obtained from a call to new. In the first example, it only "works" (where "works" really means "the behavior is undefined but it still appears to function correctly) because all three pointers are to independent heap allocations.


delete this is not the correct way to call a destructor in modern code. In general you shouldn't have to call the destructor: their magic is that they are called at the appropriate time:

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

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

delete in all cases is for releasing memory allocated by new. delete this will then cause trouble when the object was not allocated by new:

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

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

This will crash your program on almost all platforms with an actual operating system ("almost all" because this is technically undefined behavior and a standards-compliant program is allowed to corrupt itself and continue running in this case, keep your fingers crossed that your platform does more than let you hobble along with corrupted memory management data structures and an invalid stack).


Placement new is largely meant for hardware device drivers or other places where a pointer must be allocated at a special address. In general you won't want to destroy objects allocated with placement new. In cases where you want to, simply call the destructor directly:

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

But, remember, Bjarne Stroustrup said, "explicit calls of destructors ... should be avoided wherever possible. Occasionally, they are essential. ... A novice should think thrice before calling a destructor explicitly and also ask a more experienced colleague before doing so" (The C++ Programming Language, 10.4.11).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜