I'm trying to use the C++0x unique_ptr
class inside a map
like so:
// compile with `g++ main.cpp -std=gnu++0x` #include <string.h> #include <map> #include <memory> using namespace std; struct Foo { char *str; Foo(char const *str_): str(strdup(str_)) {} }; int main(void) { typedef std::map<int, unique_ptr<Foo>> Bar; Bar bar; auto a = bar.insert(Bar::value_type(1, new Foo("one"))); return 0; }
However GCC gives me the following error (shortened, I think this is the relevant part, please test on your own C++ compiler):
main.cpp:19: instantiated from here /usr/include/c++/4.4/bits/unique_ptr.h:214: error: deleted function ‘std::unique_ptr::unique_ptr(const std::unique_ptr&) [with _Tp = Foo, _Tp_Deleter = std::default_delete]’ /usr/include/c++/4.4/bits/stl_pair.h:68: error: used here
I'm really not sure what I've done wrong, this works on MSVC. I have found very similar questions, that seem alike, however their solutions do not work for me.
matt@stanley:/media/data/src/c++0x-test$ gcc --version gcc-4.4.real (Ubuntu 4.4.3-4ubuntu5) 4.4.3
std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.
No, it isn't thread-safe. Both threads can potentially move the work pointer with no explicit synchronization, so it's possible for both threads to get the same value, or both to get some invalid pointer ... it's undefined behaviour.
std::unique_ptr::getReturns the stored pointer. The stored pointer points to the object managed by the unique_ptr, if any, or to nullptr if the unique_ptr is empty.
A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it.
First: Your class Foo is really a very bad approximation of std::string. I predict lots of memory leaks. (Search for "rule of three".)
Second: A pointer is not implicitly convertible to a unique_ptr object (for safety reasons). But the templated pair constructor requires the arguments to be implicitly convertible to the respective value types. GCC seems to allow this but it is a bug. You have to create the unique_ptr object manually. Unfortunately the C++0x draft lacks the following, very useful function template that eases the creation of temporary unique_ptr objects. It's also exception-safe:
template<class T, class...Args> std::unique_ptr<T> make_unique(Args&&... args) { std::unique_ptr<T> ret (new T(std::forward<Args>(args)...)); return ret; }
In addition, let's use the new emplace function instead of insert:
auto a = bar.emplace(1,make_unique<Foo>("one"));
emplace forwards both arguments to the corresponding pair constructor.
The actual problem you witnessed is that the pair constructor tried to copy a unique_ptr even though such an object is only "movable". It seems that GCC's C++0x support is not yet good enough to handle this situation correctly. From what I can tell, my line from above should work according to the current standard draft (N3126).
Edit: I just tried the following as a workaround using GCC 4.5.1 in experimental C++0x mode:
map<int,unique_ptr<int> > themap; themap[42].reset(new int(1729));
This is also supposed to work in the upcoming standard but GCC rejects it as well. Looks like you have to wait for GCC to support unique_ptr in maps and multimaps.
I don't believe it's possible to correctly use unique_ptr
in a map::insert
yet. Here's the GCC bug for it:
Bug 44436 - [C++0x] Implement insert(&&)
and emplace*
in associative and unordered containers
It looks like it may be fixed for GCC 4.6, but it won't build from SVN on vanilla Ubuntu 10.04.1 to confirm.
This is not working as of GCC svn r165422 (4.6.0).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With