三元运算符的结果不是右值
Result of ternary operator not an rvalue
如果使用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;
这是ideone上的演示。
我在gcc 4.7.0和MSVC10上尝试过。两者行为相同
我猜发生这种情况的原因是:
三元运算符类型是一个左值,因为它是在执行返回语句之前求值的。此时,a和b还不是x值(即将过期)
这个解释正确吗?
这是标准中的缺陷吗
这显然不是预期的行为,在我看来,这是一种非常常见的情况。
以下是相关的标准报价:
12.8第32段:
在以下情况下允许复制省略[…]
- 在具有类返回类型的函数中的
return
语句中,当表达式是与函数返回类型具有相同cv非限定类型的非易失性自动对象(函数或catch子句参数除外)的名称时,可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作- [当
throw
ing时,有条件]- [当来源是临时的,有条件]
- [当
catch
按值递增时,有条件]
第33段:
当满足或将满足省略复制操作的标准时,除非源对象是函数参数,并且要复制的对象是由左值指定的,否则首先执行重载解析以选择复制的构造函数,就好像对象是由右值指定的一样。如果重载解析失败,或者所选构造函数的第一个参数的类型不是对对象类型的右值引用(可能是cv限定的),则会再次执行重载解析,将对象视为左值。[注意:无论是否会发生复制省略,都必须执行此两阶段重载解析。如果不执行省略,它将确定要调用的构造函数,并且即使调用被省略,所选构造函数也必须可访问。-结束注意]
由于return (cond ? a : b);
中的表达式不是一个简单的变量名,因此它不符合复制省略或右值处理的条件。也许有点不幸,但很容易想象一次将示例进一步扩展一点,直到您对编译器实现产生了令人头疼的期望。
当然,当您知道返回值是安全的时,您可以通过明确地对std::move
说返回值来绕过这一切。
这将修复
return cond ? std::move(a) : std::move(b);
将三元运算符视为一个函数,就像您的代码是一样
return ternary(cond, a, b);
参数不会被隐式移动,您需要使其显式。
相关文章:
- 使用++运算符会导致意外的结果
- 三元运算符在返回语句中给出意外的结果
- oStream 不打印添加两个 valarray 的结果(使用运算符重载)
- 当关系运算符的含义相同时,为什么结果不同?
- 有没有办法将 for 循环结果返回到像三元运算符这样的函数中?
- C++:比较运算符>和字符串文本的意外结果
- 为什么 == 运算符没有产生与 strcmp 相同的结果?
- 具有预分配结果C++的重载加运算符
- 使用 C++ 中的运算符重载显示不正确的结果
- 为什么当我使用额外的括号而不使用运算符重载时,插入运算符在 std::cout 中给出不同的结果?
- 为什么这个条件运算符的计算结果为 int?
- 为什么>>运算符在不同的编译器上显示不同的结果?
- 运算符的两个不同结果 - 在 c++11 中
- C++ 中的增量运算符未获得正确的结果
- 为什么在std :: string上尺寸运算符会产生意外结果
- 重载前增量运算符使用重载后增量运算符内的变量结果
- C++运算符和带枚举的计算结果为 false
- sizeof(…)运算符结果的使用令人困惑
- 根据运算符推断模板返回类型:结果
- 运算符*=来自两个实例(矩阵),结果不好