Two different types of memory are allocated here. There is memory allocated in vector for unique_ptr itself (which will not be very much, just a pointer to unique_ptr). And then dynamically allocated memory for the object managed by each unique_ptr .
You cannot allocate all the memory ahead, since the dynamically allocated memory for the object inside each unique_ptr must be allocated separately.
But if you want to avoid reallocating memory for a vector due to several insert calls, you can make a reserve first:
vec.reserve(vec.size() + n);
I doubt that this will have any effect on n just 3.
The big problem is that for each insert vector must move all the contents of vector after the insertion point by one. Moving unique_ptr cheap, but it can be augmented.
This is certainly not cleaner, but you can do it yourself using std::move_backward . Resize the vector to the required size, move all the elements along and then move unique_ptr to the elements you want to paste into:
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, possibly cleaner, way to achieve the same is to create your own custom forward iterator for use in overloading std::vector::insert(const_iterator position, InputIterator first, InputIterator last); 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));