Move-Semantik eignet sich hervorragend für RAII-Klassen. Sie erlauben es einem, so zu programmieren, als hätte man eine Wertesemantik ohne die Kosten von schweren Kopien. Ein gutes Beispiel hierfür ist returning std::vector from a function. Programmieren mit Wert-Semantik bedeutet jedoch, dass man erwarten würde, dass sich Typen wie primitive Datentypen verhalten. Diese beiden Aspekte scheinen sich manchmal zu widersprechen.Was sollte der Standardkonstruktor in einer RAII-Klasse mit Bewegungssemantik tun?
Zum einen würde man in RAII erwarten, dass der Standardkonstruktor ein vollständig initialisiertes Objekt zurückgibt oder eine Ausnahme auslöst, wenn die Ressourcenerfassung fehlgeschlagen ist. Dies garantiert, dass jedes konstruierte Objekt in einem gültigen und konsistenten Zustand ist (d. H. Sicher zu verwenden).
Auf der anderen Seite gibt es mit Bewegungssemantik einen Punkt, wenn Objekte in einem valid but unspecified state sind. In ähnlicher Weise können sich primitive Datentypen in einem nicht initialisierten Zustand befinden. Daher mit Wertesemantik, würde ich den Standardkonstruktor erwartet ein Objekt in dieser gültig, aber nicht spezifizierten Zustand zu schaffen, so dass der folgende Code das erwartete Verhalten haben würde:
// Primitive Data Type, Value Semantics
int i;
i = 5;
// RAII Class, Move Semantics
Resource r;
r = Resource{/*...*/}
In beiden Fällen würde ich erwarten, dass die " schwere "Initialisierung nur einmal auftreten. Ich frage mich, was ist die beste Vorgehensweise dabei? Offensichtlich gibt es ein kleines praktisches Problem mit dem zweiten Ansatz: Wenn der Standardkonstruktor Objekte im unspezifizierten Zustand erzeugt, wie würde man einen Konstruktor schreiben, der eine Ressource annimmt, aber keine zusätzlichen Parameter nimmt? (Das Senden von Tags kommt mir in den Sinn ...)
Bearbeiten: Einige der Antworten haben die Logik in Frage gestellt, dass Ihre Klassen wie primitive Datentypen funktionieren sollen. Ein Teil meiner Motivation kommt von Alexander Stepanov's Efficient Programming with Components, wo er über normale Typen redet. Insbesondere möchte ich folgendes Zitat nennen:
Was auch immer ein natürlicher idiomatischer Ausdruck in c [für eingebaute Typen] ist, sollte ein natürlicher idiomatischer Ausdruck für reguläre Typen sein.
Er fährt fort, fast das gleiche Beispiel wie oben zu liefern. Ist dieser Punkt in diesem Zusammenhang nicht gültig? Verstehe ich das falsch?
Bearbeiten: Da es nicht viel Diskussion gegeben hat, bin ich im Begriff, die am höchsten gewählte Antwort zu akzeptieren. Es ist wahrscheinlich keine gute Idee, Objekte im Status "bewegt aus wie" im Standardkonstruktor zu initialisieren, da jeder, der mit den vorhandenen Antworten einverstanden war, dieses Verhalten nicht erwarten würde.
Es gibt verschiedene Arten von RAII-Klassen: Es gibt solche, die Parameter zur Beschreibung der Ressource benötigen, die sie erwerben, und solche, die dies nicht tun. Welches ist deins? – Yakk
Die RAII-Klassen, die ich schreibe, sind meist Wrapper um C-Bibliotheken wie OpenGL, SDL oder FFmpeg. Manchmal erfordert das Erfassen von Ressourcen Parameter und manchmal nicht. Ich wollte das Verhalten des Standardkonstruktors für alle Wrapper allgemein definieren (um mögliche Verwirrung zu minimieren). – kloffy