首先,如果要释放分配给C ++中对象的内存,首选哪一个?显式调用析构函数或使用delete?
Object* object = new Object(...);
...
delete object;
OR
object->~Object();
其次,delete运算符是否隐式调用析构函数?
答案 0 :(得分:13)
delete
隐式调用析构函数,你不需要(更准确地说:不应该)直接调用它。
析构函数永远不会释放对象占用的内存(它可能驻留在堆栈上,而不是堆上,并且对象无法知道 - 但是,析构函数将删除对象组件分配的任何内存) )。
为了释放堆上分配的对象的内存,您必须调用delete
。
当您编写自己的类时,C ++将提供默认析构函数来释放组件对象(例如作为您的类成员的QString
)分配的内存,但是如果在构造函数中显式分配内存(或其他资源),请确保提供将显式释放这些资源的析构函数。
关于你自己的类的另一个一般规则:如果你标记任何方法virtual
,你的析构函数也应该是virtual
(即使你依赖于默认的析构函数),以便正确的析构函数被称为任何来自你的类。
答案 1 :(得分:7)
我不喜欢。
只有当您将内存分配与对象生命周期分离时,才需要非常非常少地进行显式析构函数调用。如果实现自定义容器类,则可能需要它。
显式delete
可能是破坏使用new
表达式动态创建的对象的合法方式,但在大多数应用程序代码中它应该是不必要的,因为它表示新的可能不匹配的地方并且可能会发生删除以及存在潜在异常安全问题的区域。
如果对象生命周期被约束为块,则通常应首选局部变量,因为内存分配开销通常较低,并且对象将自动被正确清理,但块将退出。
{
// ...
Object object( ... );
} // object destructor run, however this block is exited.
如果有某些原因不需要这样(例如对象的静态大小过大)或者它的生命周期无法与特定范围匹配,那么通常应该使用某种智能指针来管理对象的生命周期。标准C ++中可用的最基本的智能指针是std::auto_ptr
,它可用于块作用域动态分配的对象,但在复制和赋值时具有“令人惊讶”的行为。 tr1::shared_ptr
(或boost::shared_ptr
)之类的东西是需要共享所有权的常见替代方案。
{
std::auto_ptr<Object> object(new Object(...));
// ...
} // *object destructor run, however this block is exited.
答案 2 :(得分:4)
删除是首选。只是调用析构函数不会释放新的分配的内存。
答案 3 :(得分:4)
使用delete
。它调用对象析构函数,然后释放已分配的内存。
此外,它不是解构函数,而是析构函数。
答案 4 :(得分:4)
通常你永远不想显式调用析构函数。只需使用delete
。
答案 5 :(得分:4)
调用delete将调用析构函数,然后释放内存。
显式调用析构函数只会调用析构函数,而不会释放内存。
因此,您应该几乎总是调用delete:除非您想要在不释放内存的情况下调用析构函数,例如因为你使用placement new构建了对象。
答案 6 :(得分:2)
你永远不应该自己调用析构函数。 删除会为您调用
答案 7 :(得分:2)
需要考虑的其他事项:
因为delete
在内部调用析构函数,执行这两个操作是错误的,即调用析构函数然后删除。所以下面的代码:
Foo* px = new Foo;
// …
px->~Foo();
delete px;
会产生一个讨厌的bug。根据实际析构函数中的操作,这可能会在很长一段时间内被忽视,因为编译器实际上允许使用此代码。这可能会导致细微的,难以发现的错误。
答案 8 :(得分:1)
答案 9 :(得分:0)
当您使用动态内存分配来创建对象时,您可以使用delete运算符来销毁/删除对象,但是当您不使用DMA时,尝试使用删除操作符删除对象会引发错误。处理这种情况的一种方法是,显式编写自己的析构函数,并使用该对象调用析构函数来销毁它。