Defining a variable that is either an existing value or a new one in C++

Viewed 105

Can I make the code below work without copying the object b?

#include <iostream>
using namespace std;
class A{
        public:
                A() = default;
                A(const A& a) { cout << "copy ctor\n"; }
                A(A&& a) { cout << "move ctor\n"; }
                A& operator=(const A& a) { cout << "copy\n"; return *this;}
                A& operator=(A&& a) { cout << "move\n";  return *this;}
};

A Gen() {
        A x;
        return x;
}

int main() {
        bool cached = true;
        const A b;
        const A& a = cached ? b : Gen();
}

It seems like when cached is true, then the copy ctor is called.

*Edit: in the real code, the class A is kinda big, so I want to avoid copying. *Edit 2: I made b as constant, to clarify the intent.

2 Answers

The overall type of your conditional operator is not a reference type, because the 'false' branch is not a reference. Thus, even in the 'true' branch, the b object has to be copied, in order to match the type of the Gen() call. The assignment makes a reference to that copied object.

In your case, you can avoid this copy operation by a simple cast of the object returned by Gen() in the 'false' branch, to a reference to that object:

const A& a = cached ? b : static_cast<const A&>(Gen());

Note that this cast is being performed (implicitly) in your original code, by the assignment operator (which, if cached is false will create a reference to the returned object).

When using the ternary operator, b is handled as glvalue. That will cause a copy constructor call. If you want to avoid that, write std::move(b) which provides you with rvalue reference. In that case move constructor will be called.

More info can be found here.

Related