std :: vector :: push_back Ein nicht kopierbares Objekt verursacht einen Compilerfehler

8

Ich erhalte Kompilierungsfehler bei g++ (GCC) 4.7.2 , aber nicht bei MSVC-2012 , wenn versucht wird, std::vector::push_back ein nicht kopierbares (privater Kopierkonstruktor), aber bewegliches Objekt. Für mich sieht mein Beispiel identisch mit vielen anderen Beispielen auf SO und anderswo aus. Die Fehlermeldung lässt es als ein Problem erscheinen, dass die Struktur nicht "direkt konstruierbar" ist - ich weiß nicht, was das bedeutet, bin also doppelt unsicher, warum ein Objekt "direkt konstruierbar" sein muss, um zurückgeschoben zu werden.

> %Vor%

Gibt Fehler

%Vor%

Einfache Abhilfe aus verschiedenen Antworten:

  • Verwenden Sie MyStruct(const MyStruct&) = delete; anstelle von private ctor hack
  • Vererbt boost::noncopyable (oder eine andere Klasse mit privatem ctor)
Zero 10.12.2012, 12:20
quelle

1 Antwort

13

Der Fehler ist auf eine Einschränkung von G ++ 4.7 zurückzuführen, das DR 1170 , das sehr spät im C ++ 11-Standardisierungsprozess geändert wurde, um zu sagen, dass die Zugriffsprüfung als Teil der Template-Argumentableitung durchgeführt werden sollte.

Die zugrunde liegende Ursache ist, dass libstdc ++ vector Elemente verschiebt, wenn die move-Operation garantiert nicht geworfen wird (dh es wird noexcept oder throw() deklariert), ansonsten werden die Elemente kopiert, wenn der Typ kopierbar ist Wenn der Typ nicht kopierbar ist, aber eine möglicherweise auswerfende Verschiebungsoperation aufweist, wird er verschoben (und wenn eine Ausnahme ausgelöst wird, sind die Ergebnisse undefiniert ). Dies wird mit Prüfungen für% co_de implementiert % und is_nothrow_move_constructible Typmerkmale. In Ihrem Fall ist der Typ nicht notwow move constructible, daher wird das Merkmal is_copy_constructible überprüft. Ihr Typ hat einen Kopierkonstruktor, auf den aber nicht zugegriffen werden kann, daher erzeugt das Merkmal is_copy_constructible einen Compilerfehler mit G ++ 4.7, da die Zugriffsprüfung nicht während der Ableitung des Vorlagenarguments erfolgt.

Wenn Sie den Verschiebungskonstruktor setzen und den Zuweisungsoperator is_copy_constructible verschieben, wird der Typ verschoben und muss nicht kopierbar sein. Daher wird die noexcept Eigenschaft, die fehlschlägt, nicht verwendet und der Code wird kompiliert / p>

Alternativ, (wie auch in den Kommentaren angegeben), wenn Sie den Kopierkonstruktor löschen, erhält das is_copy_constructible Merkmal das richtige Ergebnis.

Eine andere Alternative ist die Verwendung von is_copy_constructible , die den Kopierkonstruktor implizit löscht, so dass das Merkmal boost::noncopyable ordnungsgemäß funktioniert (und auch mit älteren Compilern wie MSVC funktioniert, die gelöschte Funktionen nicht ordnungsgemäß unterstützen). Ich weiß nicht, was Sie damit meinen, es unmöglich zu machen, den Fehler zu finden, zeigt Ihnen MSVC nicht den vollen Zusammenhang eines Compilerfehlers?

  

Fazit: Verwenden Sie gegebenenfalls unique_ptr, aber machen Sie Klassen nicht explizit beweglich

Ich stimme dieser Schlussfolgerung nicht zu, es ist zu extrem. Stattdessen sollten Sie Ihre Klassen möglichst nicht bewegbar machen. Wenn möglich, verwenden Sie gelöschte Funktionen, um einen Typ nicht kopierbar anstelle von privaten + nicht implementierten Funktionen zu machen, möglicherweise unter Verwendung eines Makros für die Portabilität zu älteren Compilern, z. B.

%Vor%     
Jonathan Wakely 10.12.2012, 22:50
quelle

Tags und Links