如果使用C ++ 11编译器编译该程序,则该向量不会移出该函数。
#include <vector>
using namespace std;
vector<int> create(bool cond) {
vector<int> a(1);
vector<int> b(2);
return cond ? a : b;
}
int main() {
vector<int> v = create(true);
return 0;
}
如果您返回这样的实例,则会移动它。
if(cond) return a;
else return b;
我用gcc 4.7.0和MSVC10试了一下。两者的行为方式相同。
我猜这种情况发生的原因是这样的:
三元运算符类型是左值,因为它在执行return语句之前被计算。此时a和b还不是xvalues(即将过期)
这个解释是否正确?
这是标准中的缺陷吗?
在我看来,这显然不是预期的行为和非常常见的情况。
答案 0 :(得分:8)
以下是相关的标准报价:
12.8第32段:
在以下情况下允许复制省略 [...]
- 在具有类返回类型的函数中的
return
语句中,当表达式是具有相同cv-unqualified的非易失性自动对象(除函数或catch子句参数之外)的名称时键入函数返回类型,通过将自动对象直接构造为函数的返回值,可以省略复制/移动操作- [当
throw
时,有条件]- [当来源是临时的,有条件的时候]
- [当
catch
按值,有条件时]
第33段:
当满足或将满足复制操作的省略标准时,除了源对象是函数参数,并且要复制的对象由左值指定,重载决策以选择构造函数首先执行复制,就好像对象是由右值指定的一样。如果重载决策失败,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值。 [注意:无论是否发生复制省略,都必须执行此两阶段重载决策。如果未执行elision,它将确定要调用的构造函数,并且即使调用被省略,也必须可以访问所选的构造函数。 - 结束记录]
由于return (cond ? a : b);
中的表达式不是简单的变量名称,因此不适用于复制省略或右值处理。也许有点不幸,但很容易想象一下这个例子会稍微进一步扩展,直到你为编译器实现带来期待。
当你知道它是安全的时,你可以通过明确地告诉std::move
返回值来解决所有这些问题。
答案 1 :(得分:7)
这将解决它
return cond ? std::move(a) : std::move(b);
将三元运算符视为函数,就像代码
一样return ternary(cond, a, b);
参数不会被隐式移动,你需要明确它。