Returning const reference parameter without copying

Viewed 77

I want to return a heavy object which I pass as a const reference without copying. The code looks something like this:

#include <iostream>

class heavy_obj {
    public:
        heavy_obj() {
            std::cout << "Standard" << std::endl;
        }

        heavy_obj(const heavy_obj&) {
            std::cout << "Copy" << std::endl;
        }

        heavy_obj(heavy_obj&& t) {
            std::cout << "Move" << std::endl;
        }

};

heavy_obj return_obj_or_default(const heavy_obj& t, bool ret) {
    if(ret) {
        return std::move(t); // Copy gets called here
    } else {
        return heavy_obj();
    }
}

int main()
{
    heavy_obj t {/* Something */};
    heavy_obj t2 = return_obj_or_default(t, true);
    heavy_obj t3 = return_obj_or_default(heavy_obj(/* Something Else */), true);
    /* Output:
       Standard
       Copy
       Standard
       Copy
    */
    return 0;
}

However, if I declare the move constructor as non-const as shown above the copy constructor will be called, which I do not want. I could remove the const in the function heavy_obj return_test(heavy_obj& t, bool ret) but then I am no longer able to pass rvalues as parameters.

How do I achieve my desired behavior? Marking the parameter to the move constructor as const: heavy_obj(const heavy_obj&& t)? Though it contradicts this?

1 Answers

You can't move from a const value, so the function can't take by const &.

You could do this, so the caller has to supply an rvalue, either moving or explicitly copying lvalues they wish to pass.

heavy_obj return_obj_or_default(heavy_obj&& t, bool ret) {
    if(ret) {
        return std::move(t);
    } else {
        return heavy_obj();
    }
}

Or you could do this, so the caller doesn't have to do anything special, but it will implicitly copy lvalues.

heavy_obj return_obj_or_default(heavy_obj t, bool ret) {
    if(ret) {
        return std::move(t);
    } else {
        return heavy_obj();
    }
}
Related