13

Der folgende Code kompiliert nicht mit Visual Studio 2013:Verschieben Zuordnung von Vektor von nicht-beweglichen nicht-kopierbaren Objekten lässt sich nicht kompilieren

#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); 
} 

Die Fehlermeldung sagt

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

Das macht Kein Sinn für mich. Sie sollten den Verschiebungskonstruktor für X nicht benötigen, um eine vector<X> zu verschieben. Ist das ein Compiler Bug, oder fehlt mir etwas? Hier

ist die komplette Fehlermeldung:

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 
    ] 
+2

Ist das nicht ein Fehler im Standardzuordner? http://open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#2103 http://rextester.com/LCFA56035 – dyp

+2

Sie können diese auch aktualisieren, um Ihre Spekulation für ** warum * einzuschließen * Sie * brauchen * keine Move-Konstruktion auf Objektebene, um dies auszuführen. Einige Leser, die das sehen, verstehen vielleicht nicht, warum Sie denken, dass es ohne Klärung nicht gebraucht wird. Mein Verdacht ist @dyp ist richtig; der Zuordner ist entweder nicht für "propagate_on_container_move_assignment" (C++ 14, btw) konfiguriert oder ignoriert denselben. – WhozCraig

+0

Wie geschrieben, kompiliert für mich auf gcc 4.7.2. Aber kannst du dann deinem "Vektor " niemals etwas hinzufügen? – Barry

Antwort

11

Wie von dyp in den Kommentaren erwähnt, ist dies ein reported bug in C++11 *.Der Ausdruck

a = rv 

(wo a ist ein Container vom Typ X mit Elementtyp T und rv ist ein nicht-const rvalue vom Typ X)
hatten die folgende Anforderung in der Tabelle 99 „Zuweiser-aware Behälter Anforderungen ":

Wenn allocator_traits<allocator_type>::propagate_on_container_move_assignment ::value false ist, T ist MoveInsellable in X und MoveAssignable. Alle vorhandenen Elemente von a sind entweder Bewegung zugeordnet oder zerstört.

allocator_traits hatte die folgende Definition von propagate_on_container_move_assignment:

typedefsiehe untenpropagate_on_container_move_assignment;

Typ:Alloc::propagate_on_container_move_assignment wenn eine solche Art existiert,
sonst false_type.

Das Problem war, dass man die entsprechende typedef in std::allocator, so propagate_on_container_move_assignment war immer false zu setzen vergessen. Dies wurde für C++ 14 gelöst, indem einfach typedef hinzugefügt wurde.

* Beachten Sie, dass [default.allocator] und [allocator.traits.types] tatsächlich in §20.6 in N3337, nicht §20.7 sind.

+4

Der Grund, warum 'propagate_on_container_move_assignment' hier so wichtig ist, hat mit der Deallokation zu tun: Wenn der Allokator nicht propagiert wird, muss der Allokator auf den lhs der Zuweisung in der Lage sein, den mit dem Allokator der rhs zugewiesenen Speicher aufzuheben. Dies ist nur zulässig, wenn die Zuordnungsobjekte gleich sind - eine Laufzeitentscheidung. Wenn sie nicht gleich sind, können Sie den Speicher nicht wiederverwenden und müssen die einzelnen Elemente verschieben. Da es sich um eine Laufzeitentscheidung handelt, muss die move-Zuweisung unterstützt werden. – dyp

3

Antwort für C++ 11: VS ist richtig, denn nach this Defekt Bericht, der Spezifikation der std::allocator

auf die führt nicht benötigte Anforderungen (MoveInsertable und MoveAssignable des Werttyps) auf dem Verschiebungszuweisungsoperator von Containern mit dem Standardzuordner.

Dies wurde jedoch in C++ 14 behoben. So, jetzt std::allocator nicht diesen Code macht illegal mehr und gemäß Tabelle 96 in N3797, ([20.2.1, container.requirements.general]), die Voraussetzung für das Template-Argument T von std::vector<T> =: X ist

Benötigt: T ist löschbar von X

der wahr ist und a = rv für einen Wert vom Typ aX und einen nicht-cpnst r-Wert rv vom Typ X auf die Anforderung eines

a soll auf der Wert gleich sein, die rv vor dieser Zuordnung hatte,

, so dass keine weitere Anforderung an T. Ich habe keine weiteren Anforderungen an T in [23.3.6, vector] gefunden, also sollte dies in C++ 14 der Gesetzestext sein (wie der Defektbericht suggeriert).

+0

Fehlerlösungen gelten als rückwirkend für das Dokument, gegen das sie eingereicht wurden. Daher sollten wir stattdessen sagen, dass VS der ursprünglichen Spezifikation folgte und als Ergebnis falsch ist. –

Verwandte Themen