user1810087
user1810087

Reputation: 5334

Compiler won't use copy assignment instead move?

I have a class where the move assignment is explicit deleted, since the object should not be moveable. But if i assign to an instance of this class using RVO the compiler gives me the error:

main.cpp:12:16: note: candidate function has been explicitly deleted

also the compiler is mentioning the existing copy assignment operator but does not use it.

here is my code (or a (not) running example here):

class foo {
public:
    foo() {}
    foo(foo const& r) {}
    foo(foo&&) = delete;

    foo const& operator=(foo const& r) { return *this; }
    foo const& operator=(foo&& r) = delete;
};

int main(int argc, char **argv) {
    foo bar;
    bar = foo();
    return 0;
}

I found a quite similar post here.

I know I can avoid this by using a temporary. i wonder why every compiler (i tested this with gcc, clang and vs2013) is not able to call the existing copy assignment directly? Is there something I am missing?

Upvotes: 4

Views: 3359

Answers (3)

R. 久蔵
R. 久蔵

Reputation: 187

Just like std::move() applies a static_cast<>() to force the use of the move assignment/constructor, one can do something similar to force the use of the copy assignment/constructor:

#include <iostream>

class foo
{
public:

    foo() {}
    foo(foo const& r) {}
    foo(foo&&) = delete;

    foo const& operator=(foo const& r) { std::cout << ":)\n"; return *this; }
    foo const& operator=(foo&& r) = delete;
};

int main(int argc, char **argv)
{
    foo bar;
    bar = static_cast<const foo&>(foo());
    return 0;
}

Upvotes: 1

eerorika
eerorika

Reputation: 238311

The copy assignment is not called, because the (deleted) move assignment is a better match for overload resolution.

Simply don't declare the move assignment at all. Then the copy assignment will be selected. The implicit move assignment operator won't be generated because the class has a user declared copy constructor, move constructor and copy assignment operator. Any of those will prevent the generation of the implicit move assignment operator.


But if i assign to an instance of this class using RVO

There is no RVO involved here. You create a temporary foo and copy assign it to an existing variable. Copy assignments cannot be elided.

Also, it's quite unusual and inefficient to return by value from an assignment operator.

Upvotes: 4

wally
wally

Reputation: 11002

You could use placement new to do this:

#include <iostream>
#include <string>
#include <new>

class foo {
public:

    foo() {}
    foo(foo const& r) {}
    foo(foo&&) = delete;

    foo const& operator=(foo const& r) { return *this; }
    foo const& operator=(foo&& r) = delete;
};

int main(int argc,char **argv)
{
    foo bar;

    //bar = foo();
    bar.~foo();
    new(&bar) foo();

    return 0;
}

Upvotes: 0

Related Questions