调用析构函数方法比较

发布于 2024-10-07 10:47:32 字数 1814 浏览 9 评论 0原文

我只是想知道这三种调用析构函数的方法是否有任何显着/严重的差异。考虑以下代码。另请考虑 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]);
}

也许内存填充和/或对齐可能是原因?


相关主题:销毁对象放置新后未调用析构函数

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

獨角戲 2024-10-14 10:47:32

是的,这些方法之间存在巨大差异:

  • 在destroyApproach1中,您只调用对象的析构函数;您实际上并没有释放它占用的内存。

  • destroyApproach2destroyApproach3 中,您调用对象的析构函数释放该对象占用的内存(通过使用>删除表达式)。在第一个 TestUsingPlacementNew 测试中,这两种方法也是错误的,因为对象占用的内存最初是通过调用 malloc 分配的,而不是通过 new 分配的。代码>.

上次测试中出现运行时错误是因为您尝试删除数组中索引1处的对象;指向该元素的指针最初并不是通过调用 new 获得的。在第一个示例中,它仅“有效”(其中“有效”实际上意味着“行为未定义,但它似乎仍然可以正确运行),因为所有三个指针都指向独立的堆分配。

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.

与往事干杯 2024-10-14 10:47:32

delete this 不是在现代代码中调用析构函数的正确方法。一般来说,您不必调用析构函数:它们的魔力在于它们在适当的时间被调用:

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

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

在所有情况下,delete 都是为了释放由 new 分配的内存。当对象不是由 new 分配时,delete this 将会导致麻烦:

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

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

这将使您的程序在几乎所有具有实际操作系统的平台上崩溃(“几乎所有”,因为这在技​​术上是未定义的行为,并且在这种情况下,允许符合标准的程序损坏自身并继续运行,请祈祷您的平台所做的不仅仅是让您在损坏的内存管理数据结构和无效堆栈中蹒跚而行。


放置new主要用于硬件设备驱动程序或其他必须在特殊地址分配指针的地方。 一般来说,您不想销毁通过放置分配的对象。如果您愿意,只需直接调用析构函数:

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

但是,请记住,Bjarne Stroustrup 说:“应尽可能避免显式调用析构函数。有时,它们是必要的。...新手应该三思而后行。显式调用析构函数,并在这样做之前询问更有经验的同事”(C++ 编程语言,10.4.11)。

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文