2016-09-26 2 views
17

In Herb Sutter's talk at CppCon16 schlug er vor, pimpl idiom mit const std::unique_ptr (etwa 10 Minuten in) zu schreiben.Mit const std :: unique_ptr für pimpl idiom

Wie soll das mit Move Konstruktoren/Zuweisungen arbeiten? Gibt es etwas in C++ 17? Ich konnte nichts finden.

+0

Ohne die Rede gelesen zu haben, ist es offensichtlich, dass Klassen mit Pimpl nicht kopierbar/beweglich sind. Sie würden in dynamischem Umfang instanziiert und ausschließlich über intelligente Zeiger aufgerufen, wobei pimpl die internen Implementierungsdetails verbergen würde. –

+6

Warum willst du nicht, dass die Mehrheit deiner Pimpl Klassen beweglich ist?Es scheint eine vollkommen vernünftige Sache zu sein. –

+1

@DenisYaroshevskiy kann nur annehmen, dass er einen bestimmten Anwendungsfall im Sinn hat. Im Allgemeinen stimme ich der Verwendung von "unique_ptr" als Container für pimpl zu. Wenn Sie möchten, dass es kopierbar ist, müssen Sie dies natürlich in Bezug auf einen Klonvorgang implementieren. –

Antwort

2

Wie soll das mit Move Konstruktoren/Zuweisungen funktionieren?

Move constructors:

Die implizit deklarierte oder ausgefallenen bewegen Konstruktor für Klasse T definiert ist als gelöscht, wenn eine der folgenden Bedingungen erfüllt sind:

  • T hat nicht- statische Datenelemente, die nicht verschoben werden können (gelöschte, nicht zugreifbare oder mehrdeutige Verschiebungskonstruktoren)

const std::unique_ptr ist ein solches Datenelement wegen const.

Wenn const gelöscht wird, generiert der Compiler den Move-Konstruktor und die Zuweisung, aber nicht die Kopien.


Herb erklärt, warum er const unique_ptr verwendet:

nicht-const arbeiten, aber es ist spröde, weil Standard bewegen Semantik wahrscheinlich falsch sind.

Mit const Mitglied ist es robuster, weil const Mitglieder im Konstruktor initialisiert werden muss. Und const dokumentiert, dass die Implementierung des Objekts nicht ändert, ist es nicht State oder Strategie Entwurfsmuster.

+0

Dann müsste man in diesem Fall einen Kopierkonstruktor implementieren? – vordhosbn

+0

@vordhosbn Wenn das notwendig ist. –

+0

Das stimmt, aber meine Frage war über Umzug Konstruktion/Auftrag. Durch die Verwendung von plain unique_ptr anstelle von const bleibt die Konstruktion/Zuweisung lebendig und gut erhalten, während es const verbietet. Ich dachte, dass const Datenmitglieder eine schlechte Übung ist (wegen dieses Problems), aber anscheinend denkt Herb Sutter das nicht. Ich fragte mich warum. –

8

Wenn Ihre Klasse niemals leer sein soll, ist ein nicht-konstantes eindeutiges ptr (mit Standardverschiebung/-zuweisungen) nicht geeignet. Die Bewegungen ctor und move assign werden beide rhs leeren.

Ein const unique ptr wird diese automatischen Methoden deaktivieren, und wenn Sie verschieben möchten, müssen Sie es innerhalb der impl schreiben (und ein bisschen Kleber außerhalb).

Ich würde persönlich einen Wert ptr mit der Semantik schreiben, die ich will (dann Compiler schreiben den Kleber), aber mit einem const unique_ptr klingt vernünftig als erster Durchlauf.

Wenn Sie das nie-leere entspannen und es fast nie-leer machen, müssen Sie nun über die Vorbedingungen vieler Methoden und mögliche Bug-on-Bugs nachdenken.

Die größten Kosten dieser Technik, Schwierigkeiten bei der Rückgabe von Werten, gehen mit C++ 17 verloren.

+2

Wenn Sie sich von einem Objekt entfernen, wird angenommen, dass es sich in einem teilweise gebildeten Zustand befindet, so dass es nur zugewiesen und zerstört werden kann, so dass move constructor/assigment Ihre not_null Garantie nicht bricht. Sie können mit smth wie not_null von gsl kommen, um es zu wickeln, wenn Sie möchten. –

+0

@DenisYaroshevskiy Nein, es ist in welchem ​​Zustand auch immer Sie bereit sind zu garantieren? Es ist nicht "in einem teilweise gebildeten Zustand" zu sein, es sei denn, das ist was du * auswählst * zu garantieren. Eine Möglichkeit ist, fast-nie-leer zu sein und nur einmal leer zu sein. Dies ist eine Wahl, es hat Kosten und Nutzen. Die Kosten, von nie leer bis fast nie leer zu gehen, sollten nicht verworfen werden. Auch die Kosten, von fast-nie-leer bis nie-leer zu gehen. Never-empty ist einfacher *, um Korrektheit * zu garantieren, und es ist oft eine gute Idee, auf immer häufiger korrekten Code über schnellerem Code zu achten. – Yakk

+0

@Yakk selbst wenn ein verschobenes Objekt "nie leer" ist, wird nach dem Verschieben ein starker Code-Geruch verwendet.Ich würde argumentieren, dass eine pimpl-Zeigerüberprüfung, gefolgt von einer Assert/Exception, vorzuziehen ist, um Leuten zu erlauben, sich darauf zu verlassen, dass ein verschobenes Objekt in einem "Standard" -Zustand ist. Dies führt zu einem Desaster, wenn die Garantie wegen unvermeidlicher Missionskrieche nicht mehr erfüllt werden kann. Ich würde weit gehen, um zu sagen, dass es ein Anti-Pattern ist, das dem Geist von 'std :: move' widerspricht. –

Verwandte Themen