[英]Why does compiler use move constructor instead of the copy constructor
Is it ok that the following code 下面的代码可以吗
#include <iostream>
struct Foo
{
Foo() { std::cout << "Foo::Foo" << std::endl; }
~Foo() { std::cout << "Foo::~Foo" << std::endl; }
Foo(const Foo&) { std::cout << "Foo::Foo(const Foo&)" << std::endl; }
Foo& operator=(const Foo&) { std::cout << "Foo::operator=(const Foo&)" << std::endl; return *this; }
Foo(Foo&&) { std::cout << "Foo::Foo(Foo&&)" << std::endl; }
Foo& operator=(Foo&&) { std::cout << "Foo::operator=(Foo&&)" << std::endl; return *this; }
};
Foo foo()
{
Foo second;
return second;
}
int main()
{
foo();
}
produces such output: 产生这样的输出:
Foo::Foo
Foo::Foo(Foo&&)
Foo::~Foo
Foo::~Foo
Why does it call move constructor instead of the copy constructor? 为什么调用移动构造函数而不是复制构造函数?
The answer is simply because the standard says so. 答案仅仅是因为该标准是这样说的。 Section 12.8, paragraph 32:
第12.8节第32段:
When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.
当满足复制/移动操作的省略标准,但不满足异常声明的标准,并且要复制的对象由左值指定时,或者当return语句中的表达式为(可能带有括号)id-用最内层封闭函数或lambda-expression的主体或参数声明子句声明的具有自动存储持续时间的对象的表达式,首先执行重载解析以选择副本的构造函数,就好像该对象由右值指定。
And that's basically all there is to it. 基本上就是全部。 Logically, if the variable has automatic storage duration, and you
return
it, then immediately after the return, the variable will not exist any more when the local scope cleans up. 从逻辑上讲,如果该变量具有自动存储期限,并且您
return
其return
,则在返回后立即在清理本地作用域时不再存在该变量。 That is why, even though it is an lvalue, it is quite similar to an rvalue. 这就是为什么即使它是一个左值,它也非常类似于一个右值。 Because it's still technically an lvalue, this exception has to be made explicitly in the standard, and here we are.
因为从技术上讲它仍然是左值,所以必须在标准中明确地指定此异常,在这里就可以了。 Note that this whole situation is specific to
return
ing from a function, and does not include scope ending in general. 请注意,这整个情况特定于从函数
return
,并且一般不包括范围结尾。
second
is returned from foo
, and, being a local object, is treated as an rvalue (thanks to Nir Friedman for the correct explanation ). second
是从foo
返回的,并且作为本地对象被视为右值(感谢Nir Friedman的正确解释 )。 The returned Foo
object is constructed from a temporary, which binds to the move constructor. 返回的
Foo
对象是从临时对象构造的,该临时对象绑定到move构造函数。
Modern compiler should skip the move constructor call and use copy elision ( demo ). 现代编译器应跳过move构造函数调用,并使用复制省略( demo )。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.