将列表传递到直接初始化时是否使用移动或复制构造函数?
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 构造函数。
给定以下玩具代码:
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 构造函数。