Search code examples
c++insertunordered-set

why does insert in std::unordered_set call the copy constructor?


I have an std::unordered_set of pointers. If I do

int main()
{
  std::unordered_set<std::unique_ptr<int>> set;
  set.insert(std::make_unique(3));
}

everything works and insert calls the move constructor (i think). However I have a different situation that is similar to the following code

std::unordered_set<std::unique_ptr<int>> set;
void add(const std::unique_ptr<int>& obj) {set.insert(obj);}

int main
{
  std::unique_ptr<int> val = std::make_unique<int>(3);
  add(std::move(val));
}

and this does not compile. It gives

State Error C2280 'std::unique_ptr<int,std::default_delete>::unique_ptr(const std::unique_ptr<int,std::default_delete> &)': attempting to reference a deleted function

which means that it's trying to call the copy constructor (right?). So the question is: why insert doesn't move the object when it is inside a function? I tried also passing the pointer to the unique_ptr and even adding std::move pretty much everywhere but the copy constructor is always called


Solution

  • void add(const std::unique_ptr<int>& obj) 
    

    It comes down to something fundamental: you cannot move a constant object, by definition. "Move" basically means ripping the guts out of the moved-from object, and shoving all the guts into the new, moved-to object (in the most efficient manner possible, with the precision of a surgeon). And you can't do it if the moved-from object is const. It's untouchable. It must remain in its original, pristine condition.

    You should be able to do that if the parameter is an rvalue reference:

    void add(std::unique_ptr<int>&& obj) {set.insert(std::move(obj));}