You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

删除析构函数后,编译器是否仍会隐式生成默认构造函数?

删除析构函数后,编译器是否仍会隐式生成默认构造函数?

问题场景

当类中显式删除析构函数时,会出现看似矛盾的两种现象:

  1. GCC允许编译以下代码:
struct A
{
    ~A() = delete;
    int x;
    int y;
    virtual void foo()
    {
    }
};

int main()
{
    A *pmc = new A; // GCC允许编译,但会导致内存泄漏
    return 0;
}

从生成的汇编代码能看到,GCC确实隐式生成了默认构造函数:

A::A() [base object constructor]:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     edx, OFFSET FLAT:vtable for A+16
        mov     rax, QWORD PTR [rbp-8]
        mov     QWORD PTR [rax], rdx
        nop
        pop     rbp
        ret
  1. 但通过is_default_constructible trait检测时,结果为false:
cout << is_default_constructible<A>::value; // 输出false

核心疑问与解答

很多人会疑惑:is_default_constructible的结果是否代表C++标准的态度?是不是标准层面不允许生成默认构造函数,但编译器实现层面违规允许?

这种理解是错误的,两者的行为都符合C++标准,只是关注的维度不同:

  • 默认构造函数的生成:根据C++标准,只要类没有显式声明任何构造函数,即使显式删除了析构函数,编译器仍然会隐式生成默认构造函数。GCC生成该构造函数的行为完全符合标准。
  • is_default_constructible的含义:这个type trait检测的不是“默认构造函数是否存在”,而是“是否可以合法执行T t;这种默认构造表达式”。由于A的析构函数被删除,该类型是不可销毁的——标准要求,默认构造一个对象的语境需要确保对象能被正常销毁(除非是像new A这种永远不销毁的极端场景),因此is_default_constructible<A>::value返回false,这也符合标准对该trait的定义。
  • GCC允许new A的原因:new表达式只负责分配内存并构造对象,不要求立即销毁对象。标准并没有禁止构造一个不可销毁的对象,只是禁止在需要销毁它的语境下使用(比如栈上声明A a;就会编译失败),因此GCC的行为是合规的。

总结

  • 编译器会隐式生成默认构造函数,符合标准规定;
  • is_default_constructible返回false是因为该类型无法被正常销毁,符合标准对该trait的定义;
  • 两者的行为并不矛盾,只是分别对应“构造函数是否存在”和“默认构造表达式是否合法”两个不同的标准规则。

内容的提问来源于stack exchange,提问作者Yue Zhou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:57:26