根据C ++ 17标准(草稿here),[expr.new]:
如果 new-expression 创建一个类类型的对象或对象数组,则将对分配函数,释放函数和构造函数进行访问和歧义控制。 如果 new-expression 创建了一个类类型的对象数组,则可能会调用析构函数。
为什么new[]
会调用析构函数?毕竟是新。它不是删除。
答案 0 :(得分:56)
如果缓冲区中任何对象的构造引发异常,则必须销毁先前构造的对象。这需要一个可用的析构函数。
答案 1 :(得分:13)
您在标准中提到的引号中没有考虑“可能” 一词。
这意味着可能会发生析构函数的调用。如果数组中任何对象的构造引发异常,则会发生。
结合以下来自[class.dtor]/12.4
的引述 [expr.new]
的引言,很清楚。
在每种情况下,调用的上下文都是对象构造的上下文。对于由new-expression分配的构造对象,还可以通过使用delete-expression隐式调用析构函数。调用的上下文是delete-expression。 [注意: 一个类类型的数组包含多个子对象,每个子对象都调用析构函数。 -注意]也可以显式调用析构函数。 如果析构函数被调用或在
[expr.new]
,[class.base.init]
和[except.throw]
中指定,则可能会调用它。如果潜在调用的析构函数被删除或无法从调用上下文访问,则程序格式错误。
答案 2 :(得分:8)
实际情况:
#include <iostream>
int counter;
class Destruct
{
public:
Destruct()
{
if (counter++ > 5)
throw counter;
}
~Destruct()
{
std::cout << "Dtor called\n";
}
};
int main()
{
try
{
new Destruct[10];
}
catch (...){}
}
您将看到类似以下内容的输出:
Dtor called
Dtor called
Dtor called
Dtor called
Dtor called
Dtor called