给出以下玩具代码:
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::P(int x, int y)
并将 x
和 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 之前,将创建一个 P
类型的临时对象,然后使用复制/移动构造函数对其进行复制/移动。也就是说,创建的临时文件将用于复制/移动构造p
。由于在您的示例中,编译器将隐式生成移动构造函数,因此将使用它将代替隐式生成的复制构造函数,因为使用临时纯右值来构造 p
。这是就像你写的:
P p(P{x, y}); //equivalent to what happens without optimization in prior C++17
请注意,编译器可以消除此复制/移动构造。因此,如果您想查看调用了哪些构造函数,则可以使用 -fno-elide-constructor 来禁用此非强制复制 elison。
output C++17 之前使用 -fno-elide-constructors
的程序是:
parameterized ctor
move ctor
同样,如果您不提供 -fno-elide-constructors
标志,那么编译器将忽略此移动构造,您将看到 output :
parameterized ctor
C++17 及以上版本
从 C++17 有 mandatory copy elision 。这意味着这里不会创建临时涉及。对象x
将被直接构造就像你写的:
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 调用复制/移动构造函数。
关于c++ - 将列表传递到直接初始化时是否使用移动或复制构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72477155/