Senger CodeLab 🚀

Why can I not pushback a uniqueptr into a vector

September 29, 2026

Why can I not pushback a uniqueptr into a vector

Managing dynamic memory in C++ can be tricky, especially when dealing with smart pointers like unique_ptr and containers like std::vector. You might have encountered a compilation error when attempting to push_back a unique_ptr into a std::vector. This roadblock often surprises developers new to smart pointers. Why does this happen, and what are the correct ways to manage collections of uniquely owned objects? This article dives deep into the reasons behind this limitation and provides practical solutions for managing collections of unique_ptrs.

The Root of the Problem: Unique Ownership

The core issue lies in the very nature of unique_ptr: it represents exclusive ownership of a dynamically allocated object. By definition, a unique_ptr cannot be copied. When you try to push_back a unique_ptr into a std::vector, the vector attempts to create a copy to store within its internal array. This copying action is forbidden for unique_ptr, hence the compiler error. Think of it like trying to give the only key to your house to multiple people simultaneously – it simply doesn’t work.

This restriction is a crucial safety feature. It prevents multiple parts of your code from believing they own the same piece of memory, avoiding double deletion and memory corruption. Understanding this fundamental principle is key to working effectively with unique_ptr.

Consider the following incorrect code snippet:

include <memory> include <vector> int main() { std::unique_ptr<int> ptr(new int(5)); std::vector<std::unique_ptr<int>> vec; vec.push_back(ptr); // Error: copy assignment operator is deleted return 0; } 

Working with std::move

The solution to this problem is using std::move. std::move explicitly transfers ownership of the managed object from one unique_ptr to another. It doesn’t create a copy, but rather renders the original unique_ptr empty. This is exactly what we need to populate a std::vector with uniquely owned objects.

Here’s the corrected code:

include <memory> include <vector> int main() { std::unique_ptr<int> ptr(new int(5)); std::vector<std::unique_ptr<int>> vec; vec.push_back(std::move(ptr)); // Correct usage of std::move return 0; } 

After the std::move operation, ptr no longer owns the integer; ownership has been transferred to the unique_ptr within the vector.

Alternatives: Shared Ownership and Custom Deleters

If you require shared ownership semantics, consider using std::shared_ptr. This allows multiple parts of your code to safely access the same object, as the smart pointer manages the reference count and deletion automatically. This is useful in scenarios where multiple objects might need to access the same resource.

Another option is using custom deleters with unique_ptr. This provides more flexibility in resource management, especially when working with resources that require specific cleanup procedures beyond simple deletion. Custom deleters are powerful tools for advanced memory management scenarios.

Practical Example: Managing a Collection of Network Connections

Imagine managing a collection of network connections. Each connection should be uniquely owned to prevent accidental closure by another part of the code. Using std::vector<std::unique_ptr<Connection>> coupled with std::move is an ideal solution for this scenario. Each unique_ptr within the vector holds exclusive ownership of a connection, ensuring proper cleanup upon disconnection or program termination.

[Infographic Placeholder: Visualizing unique_ptr ownership transfer with std::move]

Frequently Asked Questions

Q: Can I use emplace_back instead of push_back with std::move?

A: Yes, emplace_back is generally preferred as it constructs the object in-place within the vector, potentially avoiding a temporary copy. You would use it like this: vec.emplace_back(std::move(ptr));

  • unique_ptr ensures single ownership of dynamic objects.
  • std::move is essential for transferring ownership to a vector.
  1. Create your unique_ptr.
  2. Use std::move to transfer ownership when adding to the vector.

By understanding the principles of unique ownership and using the appropriate tools like std::move, you can effectively manage collections of dynamically allocated objects in C++, writing safer and more efficient code. Explore further resources on smart pointers and memory management in C++ to solidify your understanding. This will enhance your proficiency in building robust and scalable applications. Consider exploring alternative solutions like shared pointers if your use case requires shared ownership. For more in-depth information, refer to resources like the C++ documentation on unique_ptr and shared_ptr. Also, check out this excellent blog post on Unique Pointers.

Question & Answer :
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 

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