以下是我对此所做的评论:
在下面的代码中,为了确保返回值是x值,passing std::vector to constructor and move semantics是必需的std::move吗?
std::vector<string> buildVector()
{
std::vector<string> local;
// .... build a vector
return std::move(local);
}我的理解是这是必需的。我经常看到在从函数返回std::unique_ptr时使用它,但是GManNickG做了以下评论:
我的理解是,在返回语句中,所有的局部变量都是自动的xvalue(期满值),并将被移动,但我不确定这是否只适用于返回的对象本身。所以OP应该继续把它放进去,直到我更确信它不应该是这样的。:)
有没有人能澄清std::move是否是必要的?
行为编译器是依赖的吗?
发布于 2012-04-01 19:29:56
在这种情况下,您可以保证local将作为一个右值返回。通常,编译器会执行返回值优化,但在这成为问题之前,您可能根本看不到任何实际的移动,因为local对象将直接在调用点构造。
6.6.3 "The return statement"中的相关说明
为了在选择构造函数(12.8)时解决重载问题,可以省略或与return语句相关的复制或移动操作,或将其视为右值。
为了澄清,这是说返回的对象可以从本地对象移动构造(即使在实践中RVO会完全跳过这一步)。该标准的标准部分是12.8 "Copying and moving class objects",关于副本省略和右值(感谢@Mankarse!)。
下面是一个愚蠢的例子:
#include <utility>
struct Foo
{
Foo() = default;
Foo(Foo const &) = delete;
Foo(Foo &&) = default;
};
Foo f(Foo & x)
{
Foo y;
// return x; // error: use of deleted function ‘Foo::Foo(const Foo&)’
return std::move(x); // OK
return std::move(y); // OK
return y; // OK (!!)
}这与返回实际的右值引用形成对比:
Foo && g()
{
Foo y;
// return y; // error: cannot bind ‘Foo’ lvalue to ‘Foo&&’
return std::move(y); // OK type-wise (but undefined behaviour, thanks @GMNG)
}发布于 2012-04-01 20:11:29
虽然return std::move(local)和return local都是在编译的意义上工作,但他们的行为是不同的。而且可能只有后者是故意的。
如果你写一个返回std::vector<string>的函数,你必须返回一个std::vector<string>。std::move(local)的类型为std::vector<string>&&,它是而不是a std::vector<string>,因此必须使用move构造函数将其转换为它。
该标准在6.6.3.2中规定:
表达式的值被隐式转换为出现表达式的函数的返回类型。
也就是说,return std::move(local)等同于
std::vector<std::string> converted(std::move(local); // move constructor
return converted; // not yet a copy constructor call (which will be elided anyway)而只有return local才是
return local; // not yet a copy constructor call (which will be elided anyway)这为您节省了一次操作。
给你一个简短的例子来说明这意味着什么:
struct test {
test() { std::cout << " construct\n"; }
test(const test&) { std::cout << " copy\n"; }
test(test&&) { std::cout << " move\n"; }
};
test f1() { test t; return t; }
test f2() { test t; return std::move(t); }
int main()
{
std::cout << "f1():\n"; test t1 = f1();
std::cout << "f2():\n"; test t2 = f2();
}这将输出
f1():
construct
f2():
construct
move发布于 2012-04-01 19:45:58
我认为答案是否定的。尽管官方只是注释,§5/6总结了什么表达式是/不是xvalue:
如果表达式是x值,则该表达式是
:
< .* >F211
通常,此规则的效果是命名的右值引用被视为左值,对对象的未命名的右值引用被视为rvalue;对函数的右值引用被视为左值,无论是否命名。
第一个要点似乎适用于这里。由于所讨论的函数返回值而不是rvalue引用,因此结果不会是xvalue。
https://stackoverflow.com/questions/9963974
复制相似问题