I have a std::map
of std::string
and std::unique_ptr<BaseInt>
. Basically I want to have a map with the class name as string key
and a unique pointer as the corresponding value
. And access the pointer as map["Derived1"]
etc (explained in code below).
When I iterate over the std::map
and try to push each value
to a std::vector
, I see the following error
Error C2280 '
std::unique_ptr<BaseInt,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)
': attempting to reference a deleted function CreateInstanceFromList c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\xmemory
I am on Visual Studio 2017 Version 15.9.16 MSVC 14.16.27023
The implementation code is as follows. BaseInt
is a BaseClass with an int
member and a pure virtual replaceInt()
. DerivedInt1
and DerivedInt2
implement the virtual function with different int
values and differ by a parameter in their construction.
#include "UserClass.h"
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <memory>
#include <typeinfo>
typedef std::vector<std::unique_ptr<BaseInt>> vec_type;
typedef std::map<std::string, std::unique_ptr<BaseInt>> map_type;
template<typename T> std::unique_ptr<T> createInstance(vec_type& vec) { return std::make_unique<T>(); };
template<typename T, typename U> std::unique_ptr<T> createInstance(vec_type& vec, U u) { return std::make_unique<T>(u); };
void fillVector(map_type& map)
{
vec_type my_vec;
for (auto const& it : map )
{
std::cout << it.first << std::endl;
it.second->replaceInt();
//my_vec.emplace_back(std::move(it.second)); //this line gives error
}
// idea is to be able to access the pointer as map["Derived1"]
std::cout << my_vec.size() << std::endl;
}
int main()
{
map_type my_map;
my_map.emplace("Derived1", createInstance<DerivedInt1>(my_vec, 7));
my_map.emplace("Derived2", createInstance<DerivedInt2>(my_vec));
fillVector(my_map);
return 0;
}
My intuition is somehow I am trying to call the copyconstructor of the unique_ptr
but I don't actually see how. Thanks.
So, the main problem is the const&
iterator as @ALX23z mentioned in the answer. The following change works:
for (auto it = map.begin(); it != map.end(); ++it )
{
std::cout << it->first << std::endl;
it->second->replaceInt();
my_vec.emplace_back(std::move(it->second));
}
As pointed out by multiple people, I made a basic design flaw of not using unique_ptr
as unique. I can see the problem you mentioned and I will look into the possibility of changing to a shared_ptr
or modifying the design. Thanks for all the quick response. I will update my changes here tomorrow.
After looking at the main project scenarios, I can see that the std::map
here is really just a one-time use container, so I can keep it local and pass all ownership to the std::vector
.
The line gives error because you iterate over the map via a const iterator. To apply emplace_back
on you need a non-const reference.
Also you have an error with your approach in general. unique_ptr
is a unique pointer. You cannot have more than one unique_ptr
pointing to the same object. So you cannot share them between map and a vector.
Use 2 shared_ptr, or unique_ptr with a raw pointer depending on requirements.