将列表传递到直接初始化时是否使用移动或复制构造函数?

Is the move or the copy constructor used when passing a list into a direct initialization?

给定以下玩具代码:

class P  // with compiler-generated copy constructor and move constructor
{
public:
    P(int x, int y) { }
};

int main()
{
    P p({x,y});
}

在我目前的理解中,P p({x,y});中的{x,y}是通过隐式调用构造函数P::P(int x, int y)并传递[=15=来转换为P类型的对象] 和 y 到它。通常会有优化,让这个P对象直接构造成p。不过,请问这个P::P(int x, int y)的隐式调用是移动构造函数还是复制构造函数(由编译器生成)调用的?

Usually there is optimization so that this P object is directly constructed as p. Nevertheless, may I ask if this implicit call of P::P(int x, int y) is invoked by the move constructor or the copy constructor

让我们看看在 C++17 和 C++17 之前的优化和不优化情况下会发生什么。

C++17 之前的版本

在 C++17 之前有 non-mandatory copy elision,这意味着当你写:

P p({x,y}); //here a temporary of type X will be created and then moved/copied 

在上面的语句中,在 C++17 之前,将使用 copy/move 构造函数创建 P 类型的临时变量,然后将其变为 copied/moved。即创建的临时文件将用于 copy/move 构造 p。由于在您的示例中,编译器将隐式生成一个 移动构造函数,因此将使用它代替隐式生成的复制构造函数 ,因为临时的 prvalue 是用于构造p。你写的是as-if:

P p(P{x, y}); //equivalent to what happens without optimization in prior C++17

请注意,允许编译器省略 这个copy/move 结构。因此,如果您想查看调用了哪些构造函数,则可以使用 -fno-elide-constructor 来禁用此 non-mandatory 复制 elison。 C++17之前的-fno-elide-constructors程序的output是:

parameterized ctor
move ctor

同样,如果您不提供 -fno-elide-constructors 标志,那么编译器将忽略此移动构造,您将看到 output:

parameterized ctor

C++17 及更高版本

从 C++17 开始有 mandatory copy elision。这意味着这里不会创建临时涉及。对象x会直接构造as-if你写的:

P p(x, y); //this is equivalent to what you wrote from C++17 due to mandatory copy elison

也就是说,从C++17开始,将不再创建P类型的临时对象。这意味着,标志 -fno-elide-constructors 在您的 C++17 示例中将 无效

我们保证不会从 C++17 调用 copy/move 构造函数。