Why is the copy assignment not deleted when the move assignment is declared?
Asked Answered
S

1

7
struct A
{
    A(int x)
        : n(x)
    {}

    A(A&&)
    {}

    A& operator =(A&&)
    {
        return *this;
    }

    int n;
};

int main()
{
    A a(1), b(2);

    a = b;

    if (2 == a.n)
    {
        // It SHOULD go here!
    }
}

As per the C++ standard 12.8.7:

If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted;

and 12.8.18

If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted;

The statement a = b; should trigger a compiler error. However, my compiler (VC++ 2013 RC) accepts it and calls the implicitly-defined copy assignment instead.

Is this a compiler's bug?

Update:

I have submitted this issue as a bug to microsoft.

Saprophyte answered 9/10, 2013 at 8:48 Comment(14)
"Is this a compiler's bug?" it wouldn't surprise me. MSVC handling of move ctors and move assignment op has always been lacking.Shortchange
a = b wouldn't call the copy constructor, would it?Telephony
Isn't a = b a copy-assignment here? Your quote says the copy-constructor is deleted, not the copy-assignment operator.Magma
@Useless, because the copy-assignment should have been deleted, so it will trigger an error.Saprophyte
@Saprophyte why should the copy-assignment have been deleted? Either you posted the wrong quote, or read it wrong.Telephony
@Saprophyte if there is a quote from the standard saying copy assignment is also deleted, you should include that too.Pauly
It does trigger a compilation error for a=b with GCC, looks like a bug in VC++ to me. The error message from GCC is error: use of deleted function 'A& A::operator=(const A&)' and note: 'A& A::operator=(const A&)' is implicitly declared as deleted because 'A' declares a move constructor or move assignment operatorMousseline
@juanchopanza, my fault. I have added another quote.Saprophyte
Seeing as you have a user-provided move assignment operator, I believe that you're right. This shouldn't compile.Milden
Could you please add more blank lines to your example, to make it more readable?Airway
Couldn't the compiler see that there are no more uses of b in the function and optimize it to a move?Missioner
@RedX: The compiler generally can't just transform copies into moves except for some very specific circumstances. Standard C++ says that this is a copy so that's what it is and that is why it needs the copy-assignment-operator, even if for some reason the compiler actually could decide to omit using it (or compile it down to a nop). Having the compilability of code depend on the optimization capabilities of the compiler wouldn't be a good idea afterall.Cosmotron
@Cosmotron Thanks for clarifying that, i always thought the compiler could do whatever it wanted under the 'as-if' rule.Missioner
@Missioner The "as-if" rule states that the compiler can do whatever it wants - as long as it is does not change the semantics of the code. Calling the copy constructor instead of failing to compile doesn't fall under this, and so it isn't allowed.Milden
M
2

This seems like a compiler bug indeed.

Since you have defined a user-provided move assignment operator, the copy assignment operator should be implicitly defined as deleted (as specified in 12.8.18). This is the behaviour exhibited by other compilers (gcc, for example).

Milden answered 9/10, 2013 at 9:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.