mercredi 26 août 2015

MSVC++ 2013 seems to allow assignments to temporary objects, effectively treating them as lvalues

I've come across this "feature" in MSVC++ and I'm now not sure if it's a bug or my understanding of lvalues/rvalues in C++ is just plain wrong.

I've added some seriously dumbed-down code to illustrate, but basically the issue is that MSVC++ 2013 (both base and NOV 2013 CTP compilers) allows assignment to temporary objects, which should really be rvalues and hence disallow any assignment attempts at compile time.

#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
}

Surely get_account() = acc; or account(42) = acc; is not C++ Standard's prescribed behaviour?! Both get_account() & account(42) should result in rvalues, which by definition do not allow assignments.

Incidentally, overloading member functions based on lvalue/rvalue qualifiers

...
void memberFn() const &;
void memberFn() &&;
...

which is supported in NOV 2013 CTP is not working properly or at all. I assume this is a result of failing to recognise rvalues, so that this is always an lvalue.

PS Unfortunately, I do not have an opportunity to test this with other compilers.

Aucun commentaire:

Enregistrer un commentaire