我正在尝试理解右值引用并 move C++11 的语义。
这些例子有什么区别,哪些不做 vector 拷贝?
第一个例子
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> &&rval_ref = return_vector();
第二个例子
std::vector<int>&& return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
第三个例子
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
最佳答案
第一个例子
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> &&rval_ref = return_vector();
第一个示例返回一个由 rval_ref
捕获的临时值。该临时文件的生命周期将超出 rval_ref
定义,您可以使用它,就好像您已经按值(value)捕获了它一样。这与以下内容非常相似:
const std::vector<int>& rval_ref = return_vector();
除了在我的重写中你显然不能以非常量方式使用 rval_ref
。
第二个例子
std::vector<int>&& return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
在第二个示例中,您创建了一个运行时错误。 rval_ref
现在包含对函数内部已破坏的 tmp
的引用。运气好的话,这段代码会立即崩溃。
第三个例子
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
您的第三个示例与您的第一个示例大致相同。 tmp
上的 std::move
是不必要的,实际上可能是性能悲观,因为它会抑制返回值优化。
编写代码的最佳方式是:
最佳实践
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> rval_ref = return_vector();
即就像在 C++03 中一样。 tmp
在 return 语句中被隐式视为右值。它将通过返回值优化(不复制,不 move )返回,或者如果编译器决定它不能执行 RVO,那么它 will use vector's move constructor to do the return .仅当不执行 RVO,并且返回的类型没有 move 构造函数时,才会使用复制构造函数进行返回。
关于C++11 右值和 move 语义混淆(return 语句),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4986673/