std:: vector не вызывает конструктор move с объектами, не имеющими никаких других конструкций move
В последнее время я много борюсь с конструкторами move и copy и, кажется, не могу найти awnser самостоятельно. Структура довольно проста. Класс OWUP, который содержит std:: unique_ptr для объекта (в данном примере int), класс One, который является простой оболочкой вокруг std:: vector OWUP и класс Two, который является простой оболочкой std:: vector One'S.
#include <memory>
#include <vector>
class OWUP {
public:
    OWUP()
    : data(nullptr)
    { }
    OWUP(const OWUP &) = delete;
    OWUP &operator=(const OWUP &) = delete; 
    OWUP(OWUP &&) noexcept = default;
    OWUP &operator=(OWUP &&) noexcept = default; 
    std::unique_ptr<int> data; 
};
class One {
public:
    One(std::size_t numof_datas)
    : datas(numof_datas)
    { }
    One(const One &) = delete;
    One &operator=(const One &) = delete; 
    One(One &&) noexcept = default;
    One &operator=(One &&) noexcept = default; 
    std::vector<OWUP> datas;
};
class Two {
public:
    Two(std::size_t numof_ones, std::size_t num_of_datas)
    : ones(numof_ones, One(num_of_datas))
    { }
    Two(const Two &) = delete;
    Two &operator=(const Two &) = delete; 
    Two(Two &&) noexcept = default;
    Two &operator=(Two &&) noexcept = default;
    std::vector<One> ones;
}; 
Код получает следующий код ошибки с g++ -std=c++14 example.cpp 
In file included from /usr/include/c++/7.3.1/memory:64:0,
                 from example.cpp:1:
/usr/include/c++/7.3.1/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = One; _Args = {const One&}]':
/usr/include/c++/7.3.1/bits/stl_uninitialized.h:210:18:   required from 'static _ForwardIterator std::__uninitialized_fill_n<_TrivialValueType>::__uninit_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = One*; _Size = long unsigned int; _Tp = One; bool _TrivialValueType = false]'
/usr/include/c++/7.3.1/bits/stl_uninitialized.h:255:17:   required from '_ForwardIterator std::uninitialized_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = One*; _Size = long unsigned int; _Tp = One]'
/usr/include/c++/7.3.1/bits/stl_uninitialized.h:366:39:   required from '_ForwardIterator std::__uninitialized_fill_n_a(_ForwardIterator, _Size, const _Tp&, std::allocator<_Tp2>&) [with _ForwardIterator = One*; _Size = long unsigned int; _Tp = One; _Tp2 = One]'
/usr/include/c++/7.3.1/bits/stl_vector.h:1337:33:   required from 'void std::vector<_Tp, _Alloc>::_M_fill_initialize(std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = One; _Alloc = std::allocator<One>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = One]'
/usr/include/c++/7.3.1/bits/stl_vector.h:298:27:   required from 'std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = One; _Alloc = std::allocator<One>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = One; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<One>]'
example.cpp:40:39:   required from here
/usr/include/c++/7.3.1/bits/stl_construct.h:75:7: error: use of deleted function 'One::One(const One&)'
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
example.cpp:29:3: note: declared here
   One(const One &) = delete;
   ^~~
Я изо всех сил старался заставить его использовать move проектировщики. Я также попытался создать свои собственные конструкторы move с помощью std:: move,но это привело к той же ошибке компиляции. Я знаю, что std:: vector проверяет move_if_noexcept (), но не могу понять, почему это не так.
2 ответа:
Потому что проблема здесь:
Two(std::size_t numof_ones, std::size_t num_of_datas) : ones(numof_ones, One(num_of_datas)) { }Вы не можете перейти от
Oneвы создаете здесь, вам действительно нужно скопировать из негоnumof_onesраз.
К сожалению, не существует простого способа построения
std::vector<One>размераnumof_onesБезOneконструктора по умолчанию или конструктора копирования. Выбранный вами конструктор принимаетnumof_onesкопирует одного значения, которое вы ему даете, в каждый элемент вектора.Самое простое решение, вероятно, не инициализировать
onesв списке инициализаторов конструктора, а инициализировать его в теле конструктора:Two(std::size_t numof_ones, std::size_t num_of_datas) { ones.reserve(numof_ones); for (size_t i = 0; i != numof_ones; ++i) { ones.emplace_back(num_of_datas); } }(технически вы, вероятно, могли бы использовать
std::vectorконструктор, который берет два итератора и предоставляет свой собственный пользовательский итератор, но это, вероятно, не стоит усилий).