Подтвердить что ты не робот

Перемещение назначения вектора объектов, не подлежащих копированию, не с возможностью перемещения, не компилируется

Следующий код не компилируется с Visual Studio 2013:

#include <vector>

struct X {
    X() = default;
    X(const X&) = delete;
    X& operator=(const X&) = delete;
    X(X&&) = delete;
    X& operator=(X&&) = delete;
    ~X() = default;
};

void foo()
{
    std::vector<X> v;
    std::vector<X> w;
    w = std::move(v);
}

В сообщении об ошибке указано

error C2280: 'X::X(X &&)' : attempting to reference a deleted function

Это не имеет никакого смысла для меня. Для перемещения a vector<X> вам не нужен конструктор перемещения для X. Является ли это ошибкой компилятора, или я что-то пропустил?

Вот полное сообщение об ошибке:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(600): error C2280: 'X::X(X &&)' : attempting to reference a deleted function
    Test.cpp(9) : see declaration of 'X::X'
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(723) : see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,_Ty>(_Objty *,_Ty &&)' being compiled
    with
    [
        _Ty=X
    ,   _Objty=X
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(723) : see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,_Ty>(_Objty *,_Ty &&)' being compiled
    with
    [
        _Ty=X
    ,   _Objty=X
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(872) : see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,_Ty>(std::allocator<_Ty> &,_Objty *,_Ty &&)' being compiled
    with
    [
        _Alloc=std::allocator<X>
    ,   _Ty=X
    ,   _Objty=X
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(872) : see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,_Ty>(std::allocator<_Ty> &,_Objty *,_Ty &&)' being compiled
    with
    [
        _Alloc=std::allocator<X>
    ,   _Ty=X
    ,   _Objty=X
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory(378) : see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<X,X>(_Ty *,X &&)' being compiled
    with
    [
        _Ty=X
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory(378) : see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<X,X>(_Ty *,X &&)' being compiled
    with
    [
        _Ty=X
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory(416) : see reference to function template instantiation '_FwdIt std::_Uninit_copy<_InIt,_FwdIt,std::allocator<_Ty>>(_InIt,_InIt,_FwdIt,std::_Wrap_alloc<std::allocator<_Ty>> &,std::_Nonscalar_ptr_iterator_tag)' being compiled
    with
    [
        _FwdIt=X *
    ,   _InIt=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ,   _Ty=X
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory(427) : see reference to function template instantiation '_FwdIt std::_Uninit_copy<_Iter,X,_Alloc>(_InIt,_InIt,_FwdIt,_Alloc &)' being compiled
    with
    [
        _FwdIt=X *
    ,   _Iter=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ,   _Alloc=std::_Wrap_alloc<std::allocator<X>>
    ,   _InIt=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\vector(1640) : see reference to function template instantiation '_FwdIt std::_Uninitialized_copy<_Iter,X*,std::_Wrap_alloc<std::allocator<_Ty>>>(_InIt,_InIt,_FwdIt,_Alloc &)' being compiled
    with
    [
        _FwdIt=X *
    ,   _Iter=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ,   _Ty=X
    ,   _InIt=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ,   _Alloc=std::_Wrap_alloc<std::allocator<X>>
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\vector(789) : see reference to function template instantiation 'X *std::vector<X,std::allocator<_Ty>>::_Ucopy<_Iter>(_Iter,_Iter,X *)' being compiled
    with
    [
        _Ty=X
    ,   _Iter=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\vector(789) : see reference to function template instantiation 'X *std::vector<X,std::allocator<_Ty>>::_Ucopy<_Iter>(_Iter,_Iter,X *)' being compiled
    with
    [
        _Ty=X
    ,   _Iter=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\vector(766) : see reference to function template instantiation 'void std::vector<X,std::allocator<_Ty>>::_Construct<_Iter>(_Iter,_Iter,std::forward_iterator_tag)' being compiled
    with
    [
        _Ty=X
    ,   _Iter=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\vector(766) : see reference to function template instantiation 'void std::vector<X,std::allocator<_Ty>>::_Construct<_Iter>(_Iter,_Iter,std::forward_iterator_tag)' being compiled
    with
    [
        _Ty=X
    ,   _Iter=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\vector(854) : see reference to function template instantiation 'void std::vector<X,std::allocator<_Ty>>::_Construct<std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>>(_Iter,_Iter)' being compiled
    with
    [
        _Ty=X
    ,   _Iter=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\vector(854) : see reference to function template instantiation 'void std::vector<X,std::allocator<_Ty>>::_Construct<std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>>(_Iter,_Iter)' being compiled
    with
    [
        _Ty=X
    ,   _Iter=std::move_iterator<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<X>>>>
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\vector(849) : while compiling class template member function 'void std::vector<X,std::allocator<_Ty>>::_Assign_rv(std::vector<_Ty,std::allocator<_Ty>> &&,std::false_type)'
    with
    [
        _Ty=X
    ]
    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\vector(860) : see reference to function template instantiation 'void std::vector<X,std::allocator<_Ty>>::_Assign_rv(std::vector<_Ty,std::allocator<_Ty>> &&,std::false_type)' being compiled
    with
    [
        _Ty=X
    ]
    Test.cpp(16) : see reference to class template instantiation 'std::vector<X,std::allocator<_Ty>>' being compiled
    with
    [
        _Ty=X
    ]
4b9b3361

Ответ 1

Как уже упоминалось в комментариях dyp, это сообщение об ошибке в С++ 11 *. Выражение

a = rv

(где a является контейнером типа X с типом элемента T и rv является неконстантным значением типа X) В таблице 99 было указано следующее: "Требования к контейнерам, учитывающие требования к абонентскому оборудованию":

Если allocator_traits<allocator_type>::propagate_on_container_move_assignment ::value false, T - MoveInsertable в X и MoveAssignable. Все существующие элементы a либо перемещаются, либо присваиваются или уничтожаются.

allocator_traits имело следующее определение propagate_on_container_move_assignment:

typedef см. ниже propagate_on_container_move_assignment;

Тип: Alloc::propagate_on_container_move_assignment, если такой тип существует, в противном случае false_type.

Проблема заключалась в том, что один забыл поместить соответствующий typedef в std::allocator, поэтому propagate_on_container_move_assignment всегда false. Это было разрешено для С++ 14, просто добавив typedef.

* Обратите внимание, что [default.allocator] и [allocator.traits.types] фактически находятся в §20.6 в N3337, а не в §20.7.

Ответ 2

Ответ для С++ 11:  VS прав, потому что в соответствии с этот отчет о дефекте, спецификация std::allocator

приводит к ненужным требованиям (MoveInsertable и MoveAssignable типа значения) в операторе присваивания перемещения контейнеров с распределителем по умолчанию.

Однако это было зафиксировано в С++ 14. Итак, теперь std::allocator больше не делает этот код незаконным и согласно таблице 96 в N3797 ([20.2.1, container.requirements.general]), требование для аргумента шаблона T of std::vector<T> =: X равно

Требуется: T стирается с X

которое истинно и a = rv для значения a типа X, а значение non-cpnst r rv типа X имеет требование

a должно быть равно значение rv до этого Назначение,

поэтому никаких дополнительных требований к T. Я не нашел никаких дополнительных требований к T в [23.3.6, vector], поэтому это должен быть легальный код в С++ 14 (как подсказывает отчет о дефектах).