c++vectorinitializationunique-ptrpush-back

Filling of vector with unique_pointers


I have two classes A and B.
B derives from A.
I have also vector std::vector<std::unique_ptr<A>> samples

This piece of code works:

std::vector<std::unique_ptr<A>> samples;
samples.push_back(std::make_unique<B>(param_1, param_2));

But this one doesn't:

std::vector<std::unique_ptr<A>> samples = {std::make_unique<B>(param_1, param_2)};

and generates such error:

/usr/include/c++/9/bits/stl_uninitialized.h: In instantiation of ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const std::unique_ptr<A>*; _ForwardIterator = std::unique_ptr<A>*]’:
/usr/include/c++/9/bits/stl_uninitialized.h:307:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const std::unique_ptr<A>*; _ForwardIterator = std::unique_ptr<A>*; _Tp = std::unique_ptr<A>]’
/usr/include/c++/9/bits/stl_vector.h:1582:33:   required from ‘void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const std::unique_ptr<A>*; _Tp = std::unique_ptr<A>; _Alloc = std::allocator<std::unique_ptr<A> >]’
/usr/include/c++/9/bits/stl_vector.h:626:2:   required from ‘std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = std::unique_ptr<A>; _Alloc = std::allocator<std::unique_ptr<A> >; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<std::unique_ptr<A> >]’
my_file.cpp:88:113:   required from here
/usr/include/c++/9/bits/stl_uninitialized.h:127:72: error: static assertion failed: result type must be constructible from value type of input range
  127 |       static_assert(is_constructible<_ValueType2, decltype(*__first)>::value,
      |                                                                        ^~~~~
make: *** [makefile:15: cpp] Error 1

Questions

  1. Is this error connected with lack of proper constructor in vector (interator?) or in A/B class?
  2. When I make push_back, should I do always std:move with unique_pointer or not? I ask because I have doubts if maybe without std::move there are created implicitly some copies. In other hand maybe compiler does some optimalizations and can recognize such "short" construction?

Solution

    1. Is this error connected with lack of proper constructor in vector (interator?) or in A/B class?

    Neither, this is due to the fact that the copy constructor of std::unique_ptr is implicitly deleted (due to the user-declared move constructor); you cannot copy a std::unique_ptr, you move it.

    1. When I make push_back, should I do always std:move with unique_pointer or not? I ask because I have doubts if maybe without std::move there are created implicitly some copies. In other hand maybe compiler does some optimalizations and can recognize such "short" construction?

    Yes, when invoking push_back on a vector of std::unique_ptr elements with an lvalue argument, you need to use std::move to invoke the move constructor of std::unique_ptr (and not its implicitly deleted copy constructor).

    #include <memory>
    #include <vector>
    
    int main() {
        std::vector<std::unique_ptr<int>> v;
        auto value = std::make_unique<int>(1);
    
        // v.push_back(value);                  // error (attempts to copy)
        v.push_back(std::move(value));          // lvalue "std::to_xvalue" -> move ctor
        v.push_back(std::make_unique<int>(2));  // already an rvalue -> move ctor
        return 0;
    }