未使用的默认成员初始值设定项如何改变 C++ 中的程序行为?

Fed*_*dor 7 c++ aggregate-initialization c++20

请考虑这个简短的代码示例:

#include <iostream>

struct A
{
    A() { std::cout << "A() "; }
    ~A() { std::cout << "~A() "; }
};

struct B { const A &a; };

struct C { const A &a = {}; };

int main()
{
    B b({});
    std::cout << ". ";

    C c({});
    std::cout << ". ";
}
Run Code Online (Sandbox Code Playgroud)

GCC 在这里打印(https://gcc.godbolt.org/z/czWrq8G5j

A() ~A() . A() . ~A() 
Run Code Online (Sandbox Code Playgroud)

这意味着A-object 初始化引用的生命周期b很短,但c生命周期会延长到作用域结束。

structsB和structs 之间的唯一区别在于C默认成员初始值设定项,它在 main() 中未使用,但行为仍然不同。你能解释一下为什么吗?

eer*_*ika 1

C c(...);是直接初始化的语法。重载解析将从 的构造函数中找到匹配项: 可以通过fromC的临时具体化来调用移动构造函数。是值初始化,它将使用默认的成员初始化程序。因此,默认成员初始值设定项并未被使用。从C++17开始,不需要移动构造函数,直接初始化变量;在这种情况下,直接绑定到临时的,并且生命周期会延长,直到销毁。C{}{}{}cc.aAC

B不是默认可构造的,因此重载解析将找不到匹配项。相反,自 C++20 起就使用了聚合初始化 - 在此之前它的格式是错误的。C++20 功能的设计是不更改先前有效程序的行为,因此聚合初始化的优先级低于移动构造函数。

与 的情况不同C,临时的生命周期A不会延长,因为带括号的初始化列表是一种例外情况。如果您使用花括号,它将被扩展:

B b{{}};
Run Code Online (Sandbox Code Playgroud)

  • `()` 形式不会延长临时变量的生命周期。请参阅 https://eel.is/c++draft/class.temporary#6.10 (3认同)