Sind die Bewegungssemantiken unvollständig?

8

Die Semantik zum Verschieben ersetzt die Kopiersemantik in Situationen, in denen das Kopieren ineffizient ist. Die Kopiersemantik behandelt vollständig kopierbare Objekte, einschließlich const-Objekte.

Es existiert bereits eine Vielzahl von nicht kopierbaren Objekten in C ++ 11, zum Beispiel std :: unique_ptr. Diese Objekte sind vollständig auf die Bewegungssemantik angewiesen, da die Bewegung von einem Objekt aus sie ungültig machen kann. Dies ist wichtig (imho) für beliebte Design-Muster wie RAII.

Ein Problem tritt auf, wenn ein konstant kopierbares Objekt einem Speicherbereich zugewiesen wird. Ein solches Objekt kann in keiner Weise wiederhergestellt werden.

Dies ist offensichtlich wichtig während der Lebensdauer des Objekts, wegen seiner Konstanz. Am Ende seiner Lebensdauer, wenn der Destruktor jedoch aufgerufen wird, ist das (nicht existierende) Objekt kurz nicht konstant.

Ich schlage vor, dass ein moving -Destruktor eine wertvolle Ergänzung zum Bewegungssemantikmodell sein könnte.

Betrachten Sie eine einfache Situation, in der ein unique_ptr in einem ungeordneten_set verwendet wird. Sie können insert in diesen Satz mit einem Move-Konstruktor (oder Konstrukt "emplace") einfügen, aber wenn Sie diesen Zeiger auf einen anderen ungeordneten_Satz verschieben möchten (d. H. Ihn konstant halten), wäre es unmöglich.

Wichtig, es gibt ein iterator insert((possibly const) key&&) , aber kein const key&& erase(iterator) . In der Tat wäre es unmöglich. Der Container konnte nur erweitert werden, um einen Zeiger auf den Schlüssel zurückzugeben und ihn zu vergessen.

Ein beweglicher Destruktor könnte dies lösen, zB const MyClass&& ~MyClass() , da es nur während der Zerstörung gegen const verstoßen würde (wenn der Compiler das Objekt als ungültig betrachtet).

EDIT: Ich sollte darauf hinweisen, const MyClass&& ~MyClass() const macht eigentlich mehr Sinn. Der Destruktor muss nichts ändern, sondern nur das Objekt so zerstören, als wäre es kein gültiges Handle mehr für die von ihm gesteuerte Ressource.

    
user3125280 13.01.2014, 07:12
quelle

3 Antworten

10

Imho Sie haben ein echtes Bedürfnis identifiziert.

Ihre Lösung klingt ähnlich wie das, was ich destruktive Move-Semantik genannt habe. Diese Möglichkeit wird im ursprünglichen Umzugssemantik-Vorschlag beschrieben . Ich denke, ein solches Design ist möglich, obwohl es nicht ohne Probleme ist. Soweit ich weiß, arbeitet niemand in diesem Bereich im Normenausschuss.

Es gibt einfachere Möglichkeiten, Nur-Verschiebe-Typen aus den assoziativen Containern zu extrahieren, die keine Sprachänderungen erfordern (abgesehen davon, dass type-punning ohne undefiniertes Verhalten erlaubt ist).

N3645 ist ein Vorschlag, der nur eine Bibliothek enthält Ein geschachtelter node_ptr -Typ in jeden Container. Das node_ptr ist sehr ähnlich wie ein unique_ptr . Es besitzt ein eindeutiges Eigentum an einem Knoten in einem assoziativen Container. Aber wenn Sie es dereferenzieren, erhalten Sie nicht-const Zugriff auf das value_type im Knoten, anstelle des Knotens selbst. extract und insert Mitglieder werden den assoziativen Containern hinzugefügt, so dass man Knoten (die node_ptr gehören) zu / aus den Containern einfügen und entfernen können.

Sie können dies verwenden, um einen Knoten aus einem Container zu entfernen, und dann einen Nur-Verschieben-Typ aus dem Knoten entfernen und ~node_ptr() den Knoten bereinigen, wenn Sie damit fertig sind. Das Dokument enthält dieses Beispiel, um diese Funktionalität zu demonstrieren:

%Vor%

Beachten Sie, dass s.extract ist noexcept , wie auch ~node_ptr() natürlich. Wenn die Move-Konstruktion von move_only_type noexcept ist, dann ist diese gesamte Operation noexcept . Andernfalls wird der set , wenn die Move-Konstruktion ausgelöst wird, so belassen, als wäre der Gegenstand aus set gelöscht worden.

Im Moment werden keine Fortschritte gemacht bei N3645 . Es wurde nicht zu einem Arbeitsentwurf gewählt, und ich habe kein Vertrauen, dass es jemals so sein wird.

Aktualisieren Sie C ++ 17

Ich stehe korrigiert: Die oben beschriebene Funktionalität wurde in C ++ 17 mit P0083R3 . Danke an Cosme, dass er mich in den Kommentaren darauf aufmerksam gemacht hat.

    
Howard Hinnant 13.01.2014, 16:53
quelle
2

Entschuldigung, aber die Prämisse ist fehlerhaft.

Ein unordered_set enthält nicht wirklich const Objekte. Es gibt Ihnen keinen Schreibzugriff auf die enthaltenen Elemente. Das ist nur eine Eigenschaft der Accessoren.

Es wäre möglich, eine key erase(iterator) -Funktion hinzuzufügen, die das Element nur in ein temporäres Element verschiebt. Ich bin mir nicht sicher, warum Sie dort ein key&& wollen.

Wie für const MyClass&& ~MyClass() const ist das aus drei Gründen nicht sinnvoll: dtors haben weder Rückgabetypen noch eine CV-Klassifizierung, noch wird eine Überladungsauflösung für sie durchgeführt.

    
MSalters 13.01.2014 10:34
quelle
1

Also im Grunde sagen Sie, dass es möglich sein sollte, ein const Objekt in ein anderes const Objekt zu verschieben und das Original zu zerstören?

Tut mir leid, aber ich denke, der ganze Punkt , const zu machen, ist, dies zu verhindern.

Andernfalls würde es ein Schlupfloch bilden: Sie könnten ein const -Objekt aus seinem Speicherort löschen, dann zerstören Sie ein anderes const -Objekt in den Speicherort des ersten ein (über Placement new ).

Jetzt hat das Objekt geändert , obwohl es const ... war, also war const nutzlos.

Siehe Kommentare unten ...

    
Mehrdad 15.01.2014 08:31
quelle