MSVC++ 2013 似乎允许对临时对象进行赋值,有效地将它们视为左值
Posted
技术标签:
【中文标题】MSVC++ 2013 似乎允许对临时对象进行赋值,有效地将它们视为左值【英文标题】:MSVC++ 2013 seems to allow assignments to temporary objects, effectively treating them as lvalues 【发布时间】:2015-08-27 00:08:00 【问题描述】:我在 MSVC++ 中遇到过这个“功能”,现在我不确定这是一个错误,还是我对 C++ 中的左值/右值的理解完全错误。
我添加了一些严重简化的代码来说明,但基本上问题是 MSVC++ 2013(基本和 NOV 2013 CTP 编译器)允许分配给临时对象,这实际上应该是右值,因此不允许任何分配尝试在编译时。
#include <iostream>
struct account
int value;
explicit account(int v) : value v
std::cout << "account ctor: " << value << std::endl;
account(const account & acc) : value acc.value
std::cout << "account copy ctor" << std::endl;
account(account && acc) : value acc.value
std::cout << "account move ctor" << std::endl;
account & operator=(const account & acc)
value = acc.value;
std::cout << "account copy assign" << std::endl;
return *this;
account & operator=(account && acc)
value = acc.value;
std::cout << "account move assign" << std::endl;
return *this;
;
int get_int() return 42;
account get_account()
return account(123);
int main()
//get_int() = 5; // this predictably fails to compile
// with '=' : left operand must be l-value
// everything below succeeds
get_account() = account(42); // console trace for this
// account ctor: 42
// account ctor: 123
// account move assign
account(123) = account(42); // console trace same as above
account acc(0); // account ctor: 0
account(42) = acc; // account ctor: 42
// account copy assign
get_account() = acc; // console trace same as above
get_account() = acc;
或 account(42) = acc;
肯定不是 C++ 标准规定的行为?! get_account()
和 account(42)
都应该产生右值,根据定义,右值不允许赋值。
顺便说一下,基于左值/右值限定符重载成员函数
...
void memberFn() const &;
void memberFn() &&;
...
2013 年 11 月支持的 CTP 无法正常工作或根本无法正常工作。我认为这是无法识别右值的结果,因此this
始终是左值。
PS 不幸的是,我没有机会使用其他编译器对此进行测试。
【问题讨论】:
这里在 gcc 5.1 上运行:http://ideone.com/08GbjA 我猜你的困惑源于 C++11 前“右值”(与左值相反)和 C++11 后(p)右值(与左值相反)的不同含义, xvalues, rvalues, lvalues) 【参考方案1】:据我了解,这是完全有效的 C++11。
只禁止对prvalues进行内置赋值。
来自 [5, expr]:
注意:操作符可以被重载,也就是说,当应用于类类型的表达式时赋予意义(子句 9)或枚举类型(7.2)。如前所述,重载运算符的使用被转换为函数调用 在 13.5 中。重载运算符遵守第 5 章中规定的语法规则,但 操作数类型、值类别和评估顺序被函数调用的规则替换。
所以要求
get_account() = account(42);
与任何其他成员函数调用相同
get_account().foo_bar(account(42));
这是有道理的,因为它只是一个更好的语法
get_account().operator=(account(42));
关于左值和右值的第 3.10 节也清楚地说明了这一点 [basic.lval]:
例如,内置赋值运算符期望左操作数是左值,右操作数是纯右值并产生左值作为结果。用户定义的操作符是函数,它们期望值和产量的类别由它们的参数和返回值决定 类型。
【讨论】:
哦,我明白了。感谢一百万澄清这一点!以上是关于MSVC++ 2013 似乎允许对临时对象进行赋值,有效地将它们视为左值的主要内容,如果未能解决你的问题,请参考以下文章