Давайте посмотрим на исходный код std::vector
(я заменил pointer
и _Ty
фактическими типами):
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
{ // move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());
}
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
{ // copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());
}
void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
{ // move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>{});
}
Если Node
является конструируемым для перемещения без броска или не конструируемым для копирования , вызывается _Uninitialized_move
, в противном случае вызывается _Uninitialized_copy
.
Проблема заключается в том, что тип std::is_copy_constructible_v
равен true
для Node
, если вы не объявляете конструктор перемещения явно. Это объявление удаляет конструктор копирования.
libstdc ++ реализует std::vector
аналогичным образом, но там std::is_nothrow_move_constructible_v<Node>
равно true
в отличие от MSVC, где оно false
. Итак, семантика перемещения используется, и компилятор не пытается сгенерировать конструктор копирования.
Но если мы заставим is_nothrow_move_constructible_v
стать false
struct Base {
Base() = default;
Base(const Base&) = default;
Base(Base&&) noexcept(false) { }
};
struct Node : Base {
std::unordered_map<int, std::unique_ptr<int>> map;
};
int main() {
std::vector<Node> vec;
vec.reserve(1);
}
возникает та же ошибка:
/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~