Zuweisung nach move
-
cooky451 schrieb:
Ist valid
17.6.5.15 Moved-from state of library types schrieb:
Objects of types defined in the C++ standard library may be moved from (12.8). Move operations may be explicitly specified or implicitly generated. Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state.
Lese ich aber nicht so. "valid state" bedeutet doch nicht zwangsweise, dass es zuweisbar ist. Vermute ich mal so.
Ich könnte ja ein Objekt implementieren, welches im Konstruktor ein Impl instantiiert. Eine Zuweisung leite ich direkt an die Impl weiter. Beim move verschiebe ich diese Impl aber in ein anderes Objekt und setze den Zeiger auf Impl auf 0. Damit kann ich das Objekt zwar zerstören aber nicht mehr zuweisen.
-
"valid state" bedeutet doch nicht zwangsweise, dass es zuweisbar ist.
Doch. Es ist in einem gültigen Zustand. Der (noch unspezifizierte) Wert kann dann mit einer Zuweisung festgelegt werden.
Variablen benutzen die per move bewegt wurden ist pöse.
Würde ich nicht sagen. Ich für meinen Teil designe i.A. alle Komponenten so, dass sie nach einem Move wieder im Anfangszustand sind.
Natürlich lese ich aber bei allen Bibliotheken erstmal die Doku (bzw. schaue in den Source), bevor ich irgendwelche Annahmen über die Implementierung mache.
-
tntnet schrieb:
Damit kann ich das Objekt zwar zerstören aber nicht mehr zuweisen.
Klar, kopierste halt das pimpl von dem rechten Operanden?

-
Arcoth schrieb:
Natürlich lese ich aber bei allen Bibliotheken erstmal die Doku (bzw. schaue in den Source), bevor ich irgendwelche Annahmen über die Implementierung mache.
Mach einfach keine Annahmen, außer, dass das Objekt in einem gültigen Zustand ist. Das implementierte Verhalten könnte sich später ändern oder du könntest etwas bei der Verwendung verwechseln.
Bei Boost werden jetzt ständig Move-Operationen ergänzt. Wenn man sich zum Beispiel jemals darauf verlassen hat, dassstd::moveaufboost::shared_ptrnur eine Kopie macht, hat man mit einer neueren Boost-Version auf einmal ein großes Problem. Andersherum kann man sich auch niemals darauf verlassen, dass keine Kopie gemacht wird. Man kann die Move-Unterstützung bei Boost nämlich auch bei aktuellen Versionen wieder deaktivieren.
-
tntnet schrieb:
Lese ich aber nicht so. "valid state" bedeutet doch nicht zwangsweise, dass es zuweisbar ist. Vermute ich mal so.
Sehe ich ähnlich.
Falls es eine Klasse in der Standardbibliothek gäbe, bei der bestimmte Eigenschaften erfüllt sein müssen, damit sie zuweisbar wäre, wäre sie nach einem move nicht zwingend zuweisbar.
Solche Klassen existieren aber nicht, es gibt z.B. kein gültiger Zustand, in dem std::string nicht zuweisbar wäre.
Aber allein aus dem Zitat folgt generelle Zuweisbarkeit für Klassen aus der Standardbib nicht.
-
cooky451 schrieb:
tntnet schrieb:
Damit kann ich das Objekt zwar zerstören aber nicht mehr zuweisen.
Klar, kopierste halt das pimpl von dem rechten Operanden?

Man kann natürlich einen Zuweisungsoperator schreiben, der das macht. Es ist halt nur die Frage, ob es notwendig im Sinne des Standards ist.
Ich habe mal ein Beispiel implementiert. Folgendes Programm erzeugt einen Speicherzugriffsfehler, da die Zuweisung sich darauf verlässt, dass der Zeiger auf impl gesetzt ist.
#include <algorithm> class Foo { class FooImpl { int a; }; FooImpl* impl; public: Foo() : impl(new FooImpl()) { } Foo(const Foo& o) : impl(new FooImpl(*o.impl)) { } Foo& operator =(const Foo& o) { *impl = *o.impl; return *this; } Foo(Foo&& o) : impl(o.impl) { o.impl = nullptr; } Foo& operator =(Foo&& o) { delete impl; impl = o.impl; o.impl = nullptr; return *this; } ~Foo() { delete impl; } }; int main(int argc, char* argv[]) { Foo f; Foo f2 = std::move(f); // hier wird f.impl zu nullptr f = f2; // hier wird f.impl (=nullptr) dereferenziert!!! }f ist nach dem move in dem Sinne "valid state" als dass es gelöscht werden kann, aber es kann nicht mehr weiter für die Zuweisung genutzt werden.
-
17.3.26 [defns.valid]
valid but unspecified state
an object state that is not specified except that the object’s invariants are met and operations on the object
behave as specified for its type
[ Example: If an object x of type std::vector<int> is in a valid but unspecified state, x.empty() can be
called unconditionally, and x.front() can be called only if x.empty() returns false. —end example ]
-
tntnet schrieb:
Es ist halt nur die Frage, ob es notwendig im Sinne des Standards ist.
Ne ist es nicht, mit deinen Klassen darfst du machen was du willst, aber trotzdem ist das Verhalten von der Standardbibliothek garantiert. Insofern dürfte es wohl guter Stil sein seine eigenen Klassen auch so zu designen.
-
camper schrieb:
17.3.26 [defns.valid]
valid but unspecified state
an object state that is not specified except that the object’s invariants are met and operations on the object
behave as specified for its type
[ Example: If an object x of type std::vector<int> is in a valid but unspecified state, x.empty() can be
called unconditionally, and x.front() can be called only if x.empty() returns false. —end example ]Jetzt müssen wir nur noch klären, was "...operations on the object behave as specified for its type" bedeutet. Ist es erlaubt,
Fooso zu implementieren, dass die Zuweisung nach dem move nicht klappt? Mir ist noch immer nicht klar, ob meinFoostandardkonform ist.
-
cooky451 schrieb:
tntnet schrieb:
Es ist halt nur die Frage, ob es notwendig im Sinne des Standards ist.
Ne ist es nicht, mit deinen Klassen darfst du machen was du willst, aber trotzdem ist das Verhalten von der Standardbibliothek garantiert. Insofern dürfte es wohl guter Stil sein seine eigenen Klassen auch so zu designen.
Ist es garantiert?
Sicher ist es sinnvoll es zu tun. Und auch mein
Fooist sicher schlechter Stil. Aber standardkonform ist es dennoch.
-
was "...operations on the object behave as specified for its type" bedeutet.
Da gibt es nichts zu klären, das ist vollkommen eindeutig. Es ist festgelegt, was
vector<...>::operator=tut. Daher kannst du es auch aufrufen.Ist es garantiert?
Ja.
-
Übrigens ist dein
Fooje nach Kontext nichtMoveAssignableoderMoveConstructible.§17.6.3.2 Tabelle 22 schrieb:
rv’s state is unspecified.
[ Note: rv must still meet the requirements of the library component that is using it.
The operations listed in those requirements must work as specified whether rv has been moved from or not. — end note ]