我在想:他们说如果你手动调用析构函数--你做错了什么。但情况总是这样吗?有什么反例吗?需要手动调用它,或者很难/不可能/不切实际地避免它的情况?
发布于 2013-01-07 05:39:29
如果对象是使用operator new()
的重载形式构造的,则需要手动调用析构函数,除非使用"std::nothrow
“重载:
T* t0 = new(std::nothrow) T();
delete t0; // OK: std::nothrow overload
void* buffer = malloc(sizeof(T));
T* t1 = new(buffer) T();
t1->~T(); // required: delete t1 would be wrong
free(buffer);
然而,在外部管理内存的级别相当低,就像上面显式调用析构函数一样,这是一个糟糕设计的标志。可能,它实际上不仅仅是糟糕的设计,而且是完全错误的(是的,在赋值操作符中使用显式析构函数,然后调用复制构造函数是一个糟糕的设计,而且很可能是错误的)。
对于C++ 2011,使用显式析构函数调用还有另一个原因:当使用广义联合时,有必要显式销毁当前对象,并在更改表示对象的类型时使用placement new创建一个新对象。此外,当联合被销毁时,如果当前对象需要销毁,则有必要显式调用当前对象的析构函数。
发布于 2013-01-07 06:19:01
所有的答案都描述了特定的情况,但有一个通用的答案:
每次只需要销毁对象(在C++意义上)而不释放对象所在的内存时,都会显式地调用dtor。
在内存分配/释放独立于对象构造/销毁进行管理的所有情况下,通常都会发生这种情况。在这些情况下,通过在现有内存块上放置new进行构造,并通过显式dtor调用进行销毁。
下面是一个原始的例子:
{
char buffer[sizeof(MyClass)];
{
MyClass* p = new(buffer)MyClass;
p->dosomething();
p->~MyClass();
}
{
MyClass* p = new(buffer)MyClass;
p->dosomething();
p->~MyClass();
}
}
另一个值得注意的例子是std::vector
使用的默认std::allocator
:元素是在push_back
期间在vector
中构造的,但内存是以块为单位分配的,因此它预先存在元素构造。因此,vector::erase
必须销毁元素,但不一定要释放内存(特别是在新的push_back必须很快发生的情况下…)。
在严格的OOP意义上,它是“糟糕的设计”(你应该管理对象,而不是内存:对象需要内存的事实是一个“事件”),它是“低层编程”中的“好设计”,或者是在内存不是从默认operator new
购买的“免费存储”中获得的情况下。
如果它在代码周围随机发生,那就是糟糕的设计,如果它发生在专门为此目的而设计的类的本地,那就是好的设计。
发布于 2013-01-07 05:35:44
不,你不应该显式调用它,因为它会被调用两次。一次用于手动调用,另一次是在声明对象的范围结束时。
例如:
{
Class c;
c.~Class();
}
如果你真的需要执行同样的操作,你应该有一个单独的方法。
有一个specific situation,您可能想要使用放置new
调用动态分配的对象上的析构函数,但它听起来并不是您所需要的。
https://stackoverflow.com/questions/14187006
复制相似问题