删除操作符delete()时,操作符new()的行为会有所不同,具体取决于默认构造函数的存在


17

使用运算符new()创建类C的新对象会在此处产生错误:

class C
{
public:
    C() {}
    virtual ~C() {}

    void operator delete(void*) = delete;
};


int main()
{
    C* c = new C;
}

C2280: 'void C::operator delete(void *)': function was explicitly deleted

但是,当我更换C() {} 使用C() = default; 或删除线,使编译器插入一个默认的构造函数(我相信有同样的效果= default),该代码将编译并运行。

使编译器生成的默认构造函数和用户定义的默认构造函数之间发生什么区别?

我在这篇文章中得到了一些提示,但是这里的C类(没有用户提供的构造函数)并不简单,因为析构函数是虚拟的,对吗?

与最新的Visual Studio c ++ 17一起编译。


3
不确定,但我认为不同的是默认构造函数为noexcept
Sebastian Redl

1
无法使用g ++复制。关于operator delete()构造函数是手动编写还是隐式生成的类似诊断。这符合我的期望-由于new表达式可能会引发异常,因此编译器需要access operator delete()
彼得

@SebastianRedl你是对的,添加noexcept将使代码编译,但是如何...?
yeshjho

1
@Peter异常只能由构造函数引发,因此,noexcept如SebastianRedl所述,则operator delete不必包含对的调用。同样,只有析构函数是虚拟的,g ++才会抱怨。否则,即使构造函数正在抛出,它也始终会编译。
胡桃

@LeDYoM您的链接是有关解析IP地址的,这似乎与问题无关。您是否发布了错误的链接?
LF

Answers:


17

使编译器生成的默认构造函数和用户定义的默认构造函数之间发生什么区别?

new表达式调用相应的operator new,然后调用构造函数。如果构造函数抛出异常,则new表达式必须operator new通过调用相应的来撤消的效果(以避免泄漏内存)operator delete。如果后者被删除,则newexpression无法调用它,从而导致编译器error: use of deleted function 'static void C::operator delete(void*)'

noexcept构造函数不可能抛出异常,因此,operator delete不需要相应的构造函数,因为它不会被new表达式调用。一个default微不足道的类的构造函数也是一个noexcept构造函数。虚拟析构函数的存在需要operator delete被删除,因为特殊标量删除析构函数delete通过基类指针启用表达式的实现细节)会调用operator delete

C ++标准似乎未指定是否必须要求operator delete不删除编译器,即使编译器可能无法通过new表达式调用它也是如此。gcc,但是,如果它是d(发布了错误报告),似乎根本就不会调用相应operator deletenew表达式。delete

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.