移动不可移动非可复制对象的向量分配不会编译

Joh*_*åde 14 c++ language-lawyer move-semantics c++11 visual-studio-2013

以下代码无法使用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);
}
Run Code Online (Sandbox Code Playgroud)

错误消息说

error C2280: 'X::X(X &&)' : attempting to reference a deleted function
Run Code Online (Sandbox Code Playgroud)

这对我来说毫无意义.你不应该需要移动构造函数X来移动vector<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
    ]
Run Code Online (Sandbox Code Playgroud)

Col*_*mbo 12

正如评论中的dyp所提到的,这是C++ 11*中报告的错误.表达方式

a = rv
Run Code Online (Sandbox Code Playgroud)

(其中aX具有元素类型的类型的容器,T并且rv是类型的非常量值X)
在表99"具有分配器的容器要求"中具有以下要求:

如果allocator_traits<allocator_type>::propagate_on_container_move_assignment ::valuefalse,TMoveInsertableXMoveAssignable.所有现有元素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.只需添加typedef就可以解决C++ 14问题.

*请注意,[default.allocator]和[allocator.traits.types]实际上在N3337的§20.6中,而不是§20.7.

  • 这里`propagate_on_container_move_assignment`如此重要的原因与释放有关:如果没有传播分配器,则赋值的lhs上的分配器必须能够释放用rhs的分配器分配的内存.仅当分配器对象比较相等时才允许这样做 - 运行时决策.如果它们不相等,则无法重用内存并且必须移动各个元素.由于这是一个运行时决策,因此必须支持移动分配. (5认同)