从C ++ 17标准(草案here),[expr.new]:
如果new-expression创建一个对象或类类型的对象数组,则对分配函数,释放函数和构造函数进行访问和歧义控制。如果new-expression创建了类类型的对象数组,则可能会调用析构函数。
为什么new[]
会调用析构函数?毕竟,这是新的。它不是删除。
如果缓冲区中任何对象的构造引发异常,则必须销毁先前构造的对象。这需要一个可用的析构函数。
您没有在标准中提到的引用中考虑“潜在”一词。 这意味着可能会发生析构函数的调用。如果数组中任何对象的构造抛出异常,就会发生这种情况。
结合[class.dtor]/12.4
提到[expr.new]
的以下引用,这一点变得清晰起来。
在每种情况下,调用的上下文都是对象构造的上下文。还可以通过对new-expression分配的构造对象使用delete-expression来隐式调用析构函数。调用的上下文是delete-expression。 [注意:类类型数组包含几个子对象,每个子对象都调用析构函数。 - 结束注释]也可以显式调用析构函数。如果调用析构函数或在
[expr.new]
,[class.base.init]
和[except.throw]
中指定析构函数,则可能会调用析构函数。如果可能调用的析构函数被删除或无法从调用的上下文访问,则程序格式不正确。
在行动:
#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