2014-10-20 11 views
13

Poniższy kod nie skompilować z Visual Studio 2013:zadanie Move wektora non-ruchome-non-copyable obiektów nie skompilować

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

Komunikat o błędzie mówi

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

To sprawia, nie ma dla mnie sensu. Nie powinieneś potrzebować konstruktora ruchu dla X, aby przenieść vector<X>. Czy jest to błąd kompilatora, czy coś mi brakuje?

Oto pełna komunikat o błędzie:

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

Czy nie jest to usterka domyślnego programu przydzielającego? http://open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#2103 http://rextester.com/LCFA56035 – dyp

+2

Możesz równie dobrze zaktualizować to, aby uwzględnić spekulacje na temat ** dlaczego * * ty * nie * potrzebujesz konstrukcji przemieszczania na poziomie obiektu, aby to wykonać. Niektórzy czytelnicy, którzy to widzą, mogą nie rozumieć, dlaczego uważasz, że nie jest to potrzebne bez wyjaśnienia. Podejrzewam, że @dyp jest poprawny; alokator nie jest skonfigurowany do 'propagate_on_container_move_assignment' (C++ 14, btw) lub ignoruje to samo. – WhozCraig

+0

Tak jak napisałem, że kompiluje się dla mnie na gcc 4.7.2. Ale czy nigdy nie będziesz w stanie dodać niczego do swojego 'wektora '? – Barry

Odpowiedz

11

Jak wspomniano przez DIP w komentarzach, jest to reported bug in C++11 *.Wyrażenie

a = rv 

(gdzie a jest pojemnik typu X z elementem typu T i rv jest const RValue typu X)
miał następujący warunek w tabeli 99 „, przydzielania świadomy wymagania pojemnik ":

If allocator_traits<allocator_type>::propagate_on_container_move_assignment ::value jest false, T jest MoveInsertable w X i MoveAssignable. Wszystkie istniejące elementy z a są albo przeniesione do lub zniszczone.

allocator_traits miał następującą definicję propagate_on_container_move_assignment:

typedefpatrz niżejpropagate_on_container_move_assignment;

Typ:Alloc::propagate_on_container_move_assignment jeśli taka istnieje, typ
inaczej false_type.

Problem polegał na tym, że jeden zapomniał umieścić odpowiednią typedef do std::allocator tak propagate_on_container_move_assignment zawsze false. Zostało to rozwiązane dla C++ 14, po prostu dodając typedef.

* Należy zauważyć, że [default.allocator] i [allocator.traits.types] są faktycznie w § 20.6 w N3337, a nie §20.7.

+4

Powód, dla którego 'propagate_on_container_move_assignment' jest tak ważny, ma tutaj do czynienia z dealokacją: jeśli alokator nie jest propagowany, alokator na lhs przydziału musi być w stanie zwolnić pamięć przydzieloną z alokatorem rhs. Jest to dozwolone tylko wtedy, gdy obiekty przydzielające są równorzędne - decyzja w czasie wykonywania. Jeśli nie będą one równe, nie będzie można ponownie użyć pamięci i przenieść poszczególne elementy. Ponieważ jest to decyzja w czasie wykonywania, przeniesienie musi być obsługiwane. – dyp

3

Odpowiedź dla C++ 11: VS ma rację, bo według this raportu usterki, specyfikacji std::allocator

prowadzi do niepotrzebne wymagania (MoveInsertable i MoveAssignable typu wartości) w operatorze przypisania przenoszenia kontenerów z domyślnym przydziałem.

Zostało to jednak naprawione w C++ 14. Teraz std::allocator nie ma już ten kod i nielegalne według Tabeli 96 w N3797 ([20.2.1, container.requirements.general]), wymóg dla szablonu argumentu T z std::vector<T> =: X jest

Wymagania: T jest wymazywalna od X

, która jest zgodna i a = rv dla wartości a typu X i nie cpnst wartość r rv typu X ma wymogu

A są równe wartość, że dzieci przedtem tego zadania ,

więc nie Kolejny wymóg T. Nie znalazłem żadnych dodatkowych wymagań do T w [23.3.6, wektor], więc powinien to być kod prawny w C++ 14 (jak sugeruje raport o defektach).

+0

Uznaje się, że uchwały o wadach mają zastosowanie z mocą wsteczną do dokumentu, przeciwko któremu zostały złożone, więc powinniśmy raczej powiedzieć, że VS postępuje zgodnie z oryginalną specyfikacją i jest w błędzie. –