为什么一个new[]表达式会调用析构函数?

40
从C++17标准(草案在此)中,[expr.new]:
如果new-expression创建一个类类型的对象或对象数组,则对于分配函数、释放函数和构造函数进行访问和歧义控制。如果new-expression创建一个类类型的对象数组,则可能调用析构函数。
为什么new[]会调用析构函数?毕竟它是new,而不是delete。
3个回答

57

如果缓冲区中的任何对象构造时抛出异常,则必须销毁先前构造的对象。这需要一个可用的析构函数。


请澄清一下:这是否意味着一个新的(非数组)对象也有可能调用析构函数?从我所看到的情况来看,我认为是这样的,但我想确保它是正确的。 - Daniel Robert Miller
@DanielRobertMiller - 一个未完全构造的对象不会调用其析构函数。非数组 new 不需要可用的析构函数。 - StoryTeller - Unslander Monica

13
您在提到标准中的引文时,没有考虑到 "potentially" 这个词。它的意思是调用析构函数 可能会发生。如果数组中的任何一个对象的构造抛出异常,它将会发生
结合下面来自[class.dtor]/12.4的引文,这一点变得更加清晰了。

在每种情况下,调用的上下文都是对象构造的上下文。通过使用 new 表达式为已构造的对象分配内存,在 delete 表达式中使用也会隐含地调用析构函数;调用的上下文是 delete 表达式。[注: 类类型的数组包含多个子对象,对于每个子对象都会调用析构函数。 ——end note] 析构函数也可以显式地调用。如果调用析构函数或者按照 [expr.new], [class.base.init], 和 [except.throw] 的规定,析构函数有可能被调用。如果潜在调用的析构函数被删除或者从调用的上下文中不可访问,则程序是非法的。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接