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 似乎允许对临时对象进行赋值,有效地将它们视为左值的主要内容,如果未能解决你的问题,请参考以下文章

防止临时对象文件在 MSVC 中撞击磁盘

在 msvc 中引用一个临时的

允许对 IEnumerable<MyObj> 进行临时表达式

解构赋值--数组的解构赋值

解构赋值的用途

ECMAScript6 入门 变量的解析赋值