首页 > 解决方案 > 为什么 C++ 中类字段的默认初始化需要调用析构函数?

问题描述

请帮我完成这个程序:

struct U { 
    U(int *) noexcept;
private:
    ~U() noexcept;
};

struct B {
    B();
    ~B();
    U v; //ok
    U w{nullptr}; //ok
    U u = nullptr; //error
};

这里 structU有一个私有析构函数,仅用于证明编译器并未真正调用析构函数并简化代码长度。

而structB只声明了一个默认的构造函数和析构函数,所以编译器不会在这个翻译单元中生成它们。

structB也有 3 个字段vwu. v和字段没有问题w,但是对于字段u,编译器会发出一个关于不可访问的析构函数的错误U

error: 'U::~U()' is private within this context
   13 |     U u = nullptr; //error

演示:https ://gcc.godbolt.org/z/YooGe9xq6

问题是:

  1. 如果B::B()不在此翻译单元中编译,为什么要考虑字段默认初始化?
  2. u错误是因为为字段的初始化创建了一个临时对象吗?(没有强制复制省略?)
  3. u那么 case和wcase有什么区别呢?

标签: c++default-value

解决方案


如果 B::B() 没有在这个翻译单元中编译,为什么要考虑字段默认初始化?

因为成员初始化是类定义的一部分。因此,类定义本身是无效的,而不必涉及其构造函数的定义。在标准中,您可以从[class.mem.general]开始并遵循brace-or-equal-initializer,最终需要一个有效的“沼泽标准”赋值表达式。

错误是因为为初始化 u 字段创建了临时对象吗?(没有强制复制省略?)

是的,你的godbolt链接中的编译器错误很清楚:

<source>:13:11: error: temporary of type 'U' has private destructor
    U u = nullptr; //error

请参阅为什么 C++ 中强制 RVO 需要公共析构函数?解释为什么强制复制省略不适用(感谢@NathanPierson!)

那么 u 和 w 案例有什么区别呢?

w直接初始化而无需事先创建临时对象,因此创建它可以正常工作,因为表达式中没有任何内容尝试调用U. 显然,任何定义B::~B()仍然会失败w,但这已经超出了重点。


推荐阅读