我有一个像这样的函数,我必须在这里显式使用move还是隐式的?
std::vector<int> makeVector();
std::vector<int> makeVector2();
std::optional<std::vector<int>> getVectOr(int i) {
if(i==1) {
std::vector<int> v = makeVector();
return std::move(v);
}
else if(i==2) {
std::vector<int> v2 = makeVector2();
return std::move(v2);
}
return std::nullopt;
}
答案 0 :(得分:4)
是否使用std::move
都不重要。这里不会进行返回值优化。 RVO发生有几个要求。
返回值优化的要求之一是,返回的值必须与函数返回的类型 相同类型 。
std::optional<std::vector<int>> getVectOr(int i)
您的函数返回std::optional<std::vector<int>>
,因此只会删除 相同类型 的临时副本。在此处有问题的两个return
语句中,两个临时变量都是std::vector<int>
,它们当然不是同一类型,因此不会发生RVO。
无论发生什么情况,您都将返回std::optional<std::vector<int>>
。这是绝对的要求。没有例外。但是,从该函数返回某些内容的过程总是以std::vector<int>
开始。无论您尝试什么,都无法将其转换为完全不同的类型。在此过程中某处必须构建一些东西。没有返回值优化。
但话虽这么说:这里也有一些移动语义在起作用。如果幸运地为您排好了星星(这很有可能),那么移动语义将允许所有事情发生,而无需复制大向量的内容。因此,尽管没有进行返回值优化,但您可能会中奖,并且可以在不对所有RAM进行向量实际内容转换的情况下进行所有事情。您可以自己使用调试器来确认或拒绝您是否已通过该帐户赢得彩票。
您还可以使用另一种RVO,即从功能中return
非易失性自动作用域对象:
std::optional<std::vector<int>> getVectOr(int i) {
std::optional<std::vector<int>> ret;
// Some code
return ret;
}
也可以在此处进行返回值优化,这是可选的,但不是强制性的。
答案 1 :(得分:2)
除了已经说过的话:
在返回语句中使用std::move
禁止返回值优化。仅当return语句的操作数是在函数主体中声明的自动非易失性存储变量的名称,并且其类型等于(直到cv限定)返回类型时,才允许使用命名返回值优化。
std::move(v2)
不符合此条件。它不只是简单地命名一个变量。
命名返回值优化也不是必须的。它是可选的,并且取决于编译器是否将执行它(即使在C ++ 17中,它强制执行某些复制省略)。
但是,如果未完成返回值优化,则通常返回值将自动移动。 return
语句具有特殊的行为,如果操作数直接使用与上述类似的条件命名变量,则将执行重载解析,就好像返回值初始化程序是一个右值表达式(即使不是)一样,这样将考虑移动构造函数。无论return
语句中引用的变量的类型是否与返回类型相同,都会执行此自动移动,因此它也适用于您的示例。
不需要显式使用std::move
,如上所述,在某些情况下(尽管不是您的特定情况)这是一种悲观。因此,只需使用:
std::optional<std::vector<int>> getVectOr(int i) {
if(i==1) {
std::vector<int> v = makeVector();
return v;
}
else if(i==2) {
std::vector<int> v2 = makeVector2();
return v2;
}
return std::nullopt;
}