I have a vector:
std::vector<std::unique_ptr<int>>
and would like to insert several new unique_ptr<int>
's into it at a specified location. There is the member function std::vector::insert(iterator position, size_type n, const value_type& val)
but alas, the restrictions on copying unique_ptr
's does not allow the use of this overload.
I have read this question, however that is for inserting unique_ptr
's that already exist in another vector. I want to create new ones.
I realize I can do it with a loop, for example to insert 3 new items to the beginning of the vector:
for (int n = 0; n != 3; ++n)
vec.insert(vec.begin(), std::make_unique<int>(0));
However I'm wondering if there's a cleaner way to do this, and possibly one that allocates the new memory up-front.
Edit for clarification: the number of items to add to the vector is completely arbitrary - I wrote 3 in my example code but it could be any value and not necessarily one that's known at compile time.
Use the insert Function to Append Vector to Vector in C++ The insert method is a built-in function of the std::vector container that can add multiple elements to the vector objects. As the first example, we show how to append a given range from one vector to another.
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. D.R. Since 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))); .
Appending to a vector means adding one or more elements at the back of the vector. The C++ vector has member functions. The member functions that can be used for appending are: push_back(), insert() and emplace(). The official function to be used to append is push_back().
There is two different kinds of memory being allocated here. There is the memory allocated in the vector
for the unique_ptr
itself (which will not be very much, just a pointer per unique_ptr). And then the dynamically allocated memory for the object managed by each unique_ptr
.
You cannot allocate all the memory up-front as the dynamically allocated memory for the object within each unique_ptr
must be allocated separately.
But if you want to avoid reallocations of the memory for the vector due to multiple insert
calls you could do a reserve first:
vec.reserve(vec.size() + n);
I doubt it will have any impact for n
as small as 3 though.
More of an issue is that for each insert
the vector has to move all the contents of the vector
after the insert point along by one. Moving unique_ptr
is cheap but it could add-up.
It is certainly not cleaner, but you could do the moving yourself once using std::move_backward
. Resize the vector to the size required, move all the elements along and then move-assign the unique_ptr
in the elements where you want to insert:
auto prev_size = vec.size();
vec.resize(prev_size + 3);
auto prev_end = vec.begin() + prev_size;
std::move_backward(vec.begin(), prev_end, vec.end());
for (int n = 0; n != 3; ++n)
vec[n] = std::make_unique<int>(0);
Another, perhaps cleaner, way of achieving the same thing is to create your own custom forward-iterator to use in the std::vector::insert(const_iterator position, InputIterator first, InputIterator last);
overload of insert
:
template<typename T>
struct UniquePtrInserter : std::iterator<
std::forward_iterator_tag,
std::unique_ptr<T>,
std::ptrdiff_t,
const std::unique_ptr<T>*,
std::unique_ptr<T>>{
int n_;
public:
explicit UniquePtrInserter<T>(int n = 0) : n_(n) {}
UniquePtrInserter<T>& operator++() {n_++; return *this;}
bool operator==(UniquePtrInserter<T> other) const {return n_ == other.n_;}
bool operator!=(UniquePtrInserter<T> other) const {return !(*this == other);}
std::unique_ptr<T> operator*() const {return std::make_unique<T>(); }
};
vec.insert(vec.begin(), UniquePtrInserter<int>(0), UniquePtrInserter<int>(3));
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