Why can I not push_back a unique_ptr into a vector?
Solution 1
You need to move the unique_ptr
:
vec.push_back(std::move(ptr2x));
unique_ptr
guarantees that a single unique_ptr
container has ownership of the held pointer. This means that you can't make copies of a unique_ptr
(because then two unique_ptr
s would have ownership), so you can only move it.
Note, however, that your current use of unique_ptr
is incorrect. You cannot use it to manage a pointer to a local variable. The lifetime of a local variable is managed automatically: local variables are destroyed when the block ends (e.g., when the function returns, in this case). You need to dynamically allocate the object:
std::unique_ptr<int> ptr(new int(1));
In C++14 we have an even better way to do so:
make_unique<int>(5);
Solution 2
std::unique_ptr has no copy constructor. You create an instance and then ask the std::vector to copy that instance during initialisation.
error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>::uniqu
e_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_D
eleter = std::default_delete<int>, std::unique_ptr<_Tp, _Tp_Deleter> =
std::unique_ptr<int>]'
The class satisfies the requirements of MoveConstructible and MoveAssignable, but not the requirements of either CopyConstructible or CopyAssignable.
The following works with the new emplace calls.
std::vector< std::unique_ptr< int > > vec;
vec.emplace_back( new int( 1984 ) );
See using unique_ptr with standard library containers for further reading.
Related videos on Youtube
Comments
-
user383352 over 3 years
What is wrong with this program?
#include <memory> #include <vector> int main() { std::vector<std::unique_ptr<int>> vec; int x(1); std::unique_ptr<int> ptr2x(&x); vec.push_back(ptr2x); //This tiny command has a vicious error. return 0; }
The error:
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/mingw32/bits/c++allocator.h:34:0, from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/allocator.h:48, from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/memory:64, from main.cpp:6: c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h: In member function 'void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = std::unique_ptr<int>, _Tp* = std::unique_ptr<int>*]': c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/stl_vector.h:745:6: instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::unique_ptr<int>, _Alloc = std::allocator<std::unique_ptr<int> >, value_type = std::unique_ptr<int>]' main.cpp:16:21: instantiated from here c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h:207:7: error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_Deleter = std::default_delete<int>, std::unique_ptr<_Tp, _Tp_Deleter> = std::unique_ptr<int>]' c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/ext/new_allocator.h:105:9: error: used here In file included from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/vector:69:0, from main.cpp:7: c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h: In member function 'void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const std::unique_ptr<int>&}, _Tp = std::unique_ptr<int>, _Alloc = std::allocator<std::unique_ptr<int> >, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >, typename std::vector<_Tp, _Alloc>::_Base::_Tp_alloc_type::pointer = std::unique_ptr<int>*]': c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/stl_vector.h:749:4: instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::unique_ptr<int>, _Alloc = std::allocator<std::unique_ptr<int> >, value_type = std::unique_ptr<int>]' main.cpp:16:21: instantiated from here c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h:207:7: error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_Deleter = std::default_delete<int>, std::unique_ptr<_Tp, _Tp_Deleter> = std::unique_ptr<int>]' c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/vector.tcc:314:4: error: used here
-
UncleBens almost 14 yearsSince there can be only one, one should also be able to pass a temporary directly to the vector:
vec.push_back(std::unique_ptr<int>(new int(1)));
.unique_ptr
can also use a custom deleter (which does nothing), but then one must take into account that the address of the local variable becomes invalid at the end of the scope. -
deft_code almost 14 yearsAnother option is to use
emplace_back
. e.g.vec.emplace_back(new int(1));
-
James McNellis about 12 years@deft_code: No, that is not safe. The
emplace_back
operation can throw, and if it does, the dynamically allocatedint
will be leaked. The rule of thumb is that all dynamic allocations should be owned by a named smart pointer to avoid leakiness. -
David Stone about 11 yearsOr returned from a function: see
make_shared
. -
cdmh about 11 yearsmake_shared() returns a shared_ptr, not a unique_ptr. Unfortunately, there is no make_unique() in C++11; an unfortunate omission that hopefully will be fixed in C++14
-
FKaria over 10 years@cdmh Why would you need a
make_unique()
? I can see thatmake_shared()
allocates one bigger block of memory at the time instead of two blocks as when you usenew
, so is faster. but I don´t see the advantadge od having it forunique_ptr
. -
cdmh over 10 years@FKaria make_unique() would mean that
new
never needs to be invoked directly, which changes the programmer's mindset and avoids (significantly reduces) memory leaks. Advice like "Avoid new and delete" can then appear in the next edition of Meyers/Alexandrescu/Sutter's book :) -
Qix - MONICA WAS MISTREATED over 6 yearsSee this comment - using
emplace_x()
functions are unsafe when using smart pointers. -
Franklin Yu about 4 years
std::make_unique()
made it to C++14. Please mentioned it in the answer. -
user2189731 about 4 yearsSo what's the best way to store an unique_ptr into vector? It's extremely slow compared with raw pointer as I tested.
-
Groo about 3 years@user2189731: that's pretty strange, both
std::vector
andstd::unique_ptr
are templated classes which should allow heavy compiler optimization. The only thingstd::unique_ptr
does is prevent copy assignment, everything else should be just optimized away to raw pointer access. -
Pavel Šimerda about 3 years@cdmh On the other hand,
make_unique()
can be used with an Initializer List whilenew
can. -
yushang almost 3 years@JamesMcNellis but
std::vector<std::unique_ptr<int>> v { std::move(std::make_unique<int>(1)), };
does not work