Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning const value from arithmetic operator overload with move assignment

Tags:

c++

c++11

Let's say I have the following minimal example class:

#include <iostream>

class Foo {
public:
    Foo() = default;

    Foo(const Foo&) = default;
    Foo(Foo&&) noexcept = default;

    Foo& operator=(const Foo& rhs) {
        std::cout << "copy\n";

        return *this;
    }

    Foo& operator=(Foo&& rhs) noexcept {
        std::cout << "move\n";

        return *this;
    }

    Foo operator+(const Foo& rhs) const {
        Foo x; // with some calculation

        return x;
    }
};

int main() {
    Foo a, b, c;

    a = b + c;
}

This prints move as expected. Now according to Effective C++ Item 3, I should return const Foo from operator+ to avoid construct like a + b = c, i.e.:

// To avoid a + b = c
const Foo operator+(const Foo& rhs) const {}

Unfortunately, this suddenly starts calling copy assignment instead of move assignment operator. [I'm using gcc 4.8.4 on Ubuntu, but it is probably nothing related to compiler]

How can I ensure that a + b = c fails to compile and in the same time move assignment is called for a = b + c? Or with the introduction of move semantics, is there no way to achieve both of them in the same time?

like image 874
taskinoor Avatar asked Feb 23 '18 15:02

taskinoor


People also ask

Can assignment operator be overloaded?

You can overload the assignment operator (=) just as you can other operators and it can be used to create an object just like the copy constructor.

What is move assignment operator in C++?

In the C++ programming language, the move assignment operator = is used for transferring a temporary object to an existing object. The move assignment operator, like most C++ operators, can be overloaded. Like the copy assignment operator it is a special member function.

Why do we return reference in copy assignment operator?

A bit of clarification as to why it's preferable to return by reference for operator= versus return by value --- as the chain a = b = c will work fine if a value is returned. If you return a reference, minimal work is done. The values from one object are copied to another object.

Does std :: move CALL move assignment?

We know that std::move does not actually move anything. It just cast an lvalue reference (&) to rvalue reference (&&).


1 Answers

I have ended up using lvalue reference qualifier as pointed by Caninonos in comment and by max66 in now deleted answer (but 10k users can see it).

Foo& operator=(const Foo& rhs) & {}
Foo& operator=(Foo&& rhs) & noexcept {}

It is simple to implement and it provides a better interface design since assignment to anything other that lvalue doesn't sound meaningful and a possible source of bug.

However, it should be noted that the possibility of writing a + b = c by mistake is very low. Also compiler generated assignment operators are not lvalue reference qualified and we can write a + b = c with standard types, e.g. with std::string or with std::complex.

like image 137
taskinoor Avatar answered Sep 20 '22 13:09

taskinoor