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
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));}