c++ std::unique_ptr won't compile in map
c++, c++11, unique-ptr, visual-studio-2012
Solution
The error is because somewhere in the code, map wants to copy a `std::pair<int, std::unique_ptr<Entity>>`, however there is no copy constructor capable of this, because unique_ptr's are not copy constructable. This is specifically impossible to prevent multiple pointers owning the same memory.
So before std::move, there was no way to use an uncopiable element.
There are some solutions here.
However, in c++11 Map can make use of std::move to work with non-copyable values.
This is done by providing another insert operator, which is overloaded to include this signature:
template< class P > std::pair<iterator,bool> insert( P&& value );
This means an rvalue of a class that can be turned into a value_type can be used as an argument. The old insert is still available:
std::pair<iterator,bool> insert( const value_type& value );
This insert actually copies a value_type, which would cause an error since value_type is not copy constructable.
I think the compiler is selecting the non-templated overload, which causes the compilation error. Because it is not a template, it's failure is an error. On gcc at least, the other insert, which uses std::move, is valid.
Here is test code to see if your compiler is supporting this correctly:
#include <iostream>
#include <memory>
#include <utility>
#include <type_traits>
class Foo {
};
using namespace std;
int main() {
cout << is_constructible<pair<const int,unique_ptr<Foo> >, pair<const int,unique_ptr<Foo> >& >::value << '\n';
cout << is_constructible<pair<const int,unique_ptr<Foo> >, pair<const int,unique_ptr<Foo> >&& >::value << '\n';
}
The first line will output 0, because copy construction is invalid. The second line will output 1 since the move construction is valid.
This code:
map.insert(std::move(EntityMap::value_type(entity->getId(), std::move(entity))));
should call the move insert overload.
This code:
map.insert<EntityMap::value_type>(EntityMap::value_type(entity->getId(), std::move(entity))));
Really should call it.
EDIT: the mystery continues, vc returns the incorrect 11 for the test...
Problem
I'm currently trying to store a std::unique_ptr in a std::unordered_map, but I get a weird compile error. Relevant code: ``` #pragma once #include "Entity.h" #include <map> #include <memory> class EntityManager { private: typedef std::unique_ptr<Entity> EntityPtr; typedef std::map<int, EntityPtr> EntityMap; EntityMap map; public: /* Adds an Entity */ void addEntity(EntityPtr); /* Removes an Entity by its ID */ void removeEntity(int id) { map.erase(id); } Entity& getById(int id) { return *map[id]; } }; void EntityManager::addEntity(EntityPtr entity) { if (!entity.get()) { return; } map.insert(EntityMap::value_type(entity->getId(), std::move(entity))); } ``` This is the compile error: ``` c:\program files (x86)\microsoft visual studio 12.0\vc\include\tuple(438): error C2280: 'std::unique_ptr<Entity,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function 1> with 1> [ 1> _Ty=Entity 1> ] 1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\memory(1486) : see declaration of 'std::unique_ptr<Entity,std::default_delete<_Ty>>::unique_ptr' 1> with 1> [ 1> _Ty=Entity 1> ] 1> This diagnostic occurred in the compiler generated function 'std::pair<const _Kty,_Ty>::pair(const std::pair<const _Kty,_Ty> &)' 1> with 1> [ 1> _Kty=int 1> , _Ty=EntityManager::EntityPtr 1> ] ```