2013-05-05 5 views
7

Ist der folgende Code dazu gedacht, einen Kompilierungsfehler nach C++ 11 zu erzeugen (wenn ja, warum?) Oder ist es ein Problem mit VC11?Sortierung einer Liste von Objekten, die einen Vektor von unique_ptr enthalten

#include <vector> 
#include <list> 
#include <memory> 
struct A 
{ 
    std::vector<std::unique_ptr<int>> v; 
}; 
int main() 
{ 
    std::list<A> l; 
    l.sort([](const A& a1, const A& a2){ return true; }); 
} 

Visual C++ 2012 erzeugt die folgenden Kompilierungsfehler:

1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(606): error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' 
1>   with 
1>   [ 
1>    _Ty=int 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 11.0\vc\include\memory(1447) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr' 
1>   with 
1>   [ 
1>    _Ty=int 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(605) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' 
1>   with 
1>   [ 
1>    _Ty=std::unique_ptr<int> 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(751) : see reference to function template instantiation 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' being compiled 
1>   with 
1>   [ 
1>    _Ty=std::unique_ptr<int> 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 11.0\vc\include\type_traits(743) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled 
1>   with 
1>   [ 
1>    _Ty=std::unique_ptr<int> 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 11.0\vc\include\vector(655) : see reference to class template instantiation 'std::is_empty<_Ty>' being compiled 
1>   with 
1>   [ 
1>    _Ty=std::allocator<std::unique_ptr<int>> 
1>   ] 
1>   d:\test2\test2.cpp(213) : see reference to class template instantiation 'std::vector<_Ty>' being compiled 
1>   with 
1>   [ 
1>    _Ty=std::unique_ptr<int> 
1>   ] 
+0

Als Referenz kann ich dies in Clang und GCC gut kompilieren. Es ist also entweder dein Compiler oder deine Einstellungen. – chrisaycock

+0

@chrisaycock Oh, ich werde noch einen VC11 Fehlerbericht bei Microsoft Connect erstellen ... – PowerGamer

+3

Ich würde es lieber ganz aufgeben. –

Antwort

0

Es war ein Problem mit Visual C++ 2012 (bestätigt durch Microsoft auf Connect: Compile error in C++ code sorting a list of objects holding a vector of unique_ptr) und es wurde in Visual C++ 2013

auch schon fest, würde Ich mag, dass ein Thema hinweisen hatte nichts damit zu tun, dass Visual C++ nicht implizit Move-Konstruktoren generiert. Wenn Sie explizit alle Kopier- und Verschiebungskonstruktoren in Struktur A löschen (ja, es wird unmöglich sein, Objekte vom Typ A in die Liste einzufügen, aber das ist neben dem Punkt), soll der Code in meinem ursprünglichen Beispiel weder kopieren noch verschieben Objekte und als solche produzieren Kompilierungsfehler:

#include <vector> 
#include <list> 
#include <memory> 
struct A 
{ 
    std::vector<std::unique_ptr<int>> v; 
    A(A&&) = delete; 
    A(const A&) = delete; 
}; 
int main() 
{ 
    std::list<A> l; 
    l.sort([](const A& a1, const A& a2){ return true; }); 
} 
4

Es ist "ein Problem mit VC", aber nur, weil Sie Visual Studio sind mißbrauchen.

VC++ implementiert R-Wert-Referenzen, aber es nicht implementieren Compiler-generierte Move Constructors/Zuweisung Operatoren. Das heißt, wenn Sie möchten, dass ein Typ beweglich ist, müssen Sie selbst einen schreiben.

A ist kein beweglicher Typ, daher werden die verschiedenen std::list Funktionen versuchen, sie zu kopieren. Und sie werden versagen, wenn sie versuchen, eine vector von unique_ptr zu kopieren. Daher der Compilerfehler.

Wenn Sie bewegungsbewusste Objekte in VC++ möchten, müssen Sie Bewegungskonstruktoren/Zuweisungen für sie selbst schreiben.

+2

Warum würde das Sortieren einer Liste (kein Vektor) das Kopieren von irgendetwas erfordern? Soll die Sortierung nicht durch Änderung von "vorherigen" und "nächsten" Zeigern von doppelt verknüpften Listenknoten implementiert werden? – PowerGamer

3

Das Problem ist wirklich in VC11, wie it doesn't implement C++11 feature of automatically generating move operations (wie bereits von Nicol Bolas genagelt).

Der folgende Code wird mit VC10 SP1 kompiliert; In diesem Codebeispiel wird der Move-Konstruktor explizit geschrieben (statt operator= wird der copy-and-swap idiom verwendet).

#include <algorithm> // for std::swap (for copy-and-swap idiom) 
#include <list> 
#include <memory> 
#include <vector> 

struct A 
{ 
    std::vector<std::unique_ptr<int>> v; 

    A(A&& other) 
     : v(std::move(other.v)) 
    { 
    } 

    A& operator=(A other) 
    { 
     swap(*this, other); 
     return *this; 
    } 

    friend void swap(A& lhs, A& rhs) 
    { 
     using std::swap; 
     swap(lhs.v, rhs.v); 
    } 
}; 

int main() 
{ 
    std::list<A> l; 
    l.sort([](const A& , const A&){ return true; }); 
} 
+1

Ich bin mir ziemlich bewusst, was Move Constructor ist und die Tatsache, dass VC11 sie nicht implizit generiert. Das erklärt nicht im Geringsten, WARUM VC11 ein Objekt vom Typ A beim Sortieren einer * Liste * kopieren oder verschieben will. – PowerGamer

+0

Nun, dann können Sie die Antwort im STL-Quellcode finden. Ich verstehe deine Meinung. –

Verwandte Themen