为什么 C++ 中 class 字段的默认初始化需要调用析构函数?

Why does default initialization of a class field in C++ require destructor invocation?

请帮我完成这个程序:

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

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

这里structU有一个私有的析构函数只是为了证明析构函数不是真正被编译器调用的,为了简化代码长度

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

结构 B 也有 3 个字段:vwuvw 字段没有问题,但对于 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. 那么uw的情况有什么区别呢?

If B::B() is not compiled in this translation unit, why field default initialization is considered at all?

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

Is the error because of a temporary object created for the initialization of u field? (No mandatory copy elision?)

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

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

请参阅 了解为什么强制复制省略不适用的解释(感谢@NathanPierson!)

What is the difference between u and w cases then?

w 是直接初始化的,没有事先创建一个临时文件,所以 creating 它工作正常,因为表达式中没有任何东西试图调用 U 的析构函数.显然 B::~B() 的任何定义在 w 上仍然会失败,但这超出了重点。