Search code examples
c++c++11smart-pointerslvalue-to-rvalue

Why must a non-const reference be initialized with an lvalue?


Here is a snippet of code which causes a C2664 error:

cannot convert argument 1 from 'std::unique_ptr<Component,std::default_delete<_Ty>>' to 'ComPtr &'

So why must a non-const reference be initialized with an lvalue? How to avoid this except by declaring a new variable?

#include <memory>
#include <list>

class Component {
};

using ComPtr = unique_ptr<Component>;
using ComList = list<ComPtr>;
ComList coms;

void addComponent(ComPtr&c) {
    coms.push_back(c);
}

int main() {
    addComponent(make_unique<Component>()); //Error here.
    return 0;
}

Solution

  • The way to write this so you don't have to do what you're fighting with is: https://godbolt.org/g/vceL4q

    #include <memory>
    #include <list>
    using namespace std;
    
    class Component {
    };
    
    using ComPtr = unique_ptr<Component>;
    using ComList = list<ComPtr>;
    ComList coms;
    
    void addComponent(ComPtr c) { // <== change here
        coms.push_back(std::move(c)); // and here
    }
    
    int main() {
        addComponent(make_unique<Component>());
        return 0;
    }
    

    The c in addComponent will be created via a move constructor because the result of make_unique is an rvalue.

    It's preferred to pass in large (move friendly) data structures by value this way.