Move Konstruktor Design Frage



  • Hi,

    kann ein Objekt nachdem es "bewegt" wurde eher als ungültig oder eher als im "default" Modus angesehen werden? Diese Frage scheint mir nicht ganz unwichtig, da das Einfluss auf das Design sämtlicher Wrapperklassen um C Ressourcen hat.
    Wird ein bewegtes Objekt ungültig kann man einfach immer davon ausgehen, dass das interne Handle gültig ist. Wer dann ein bewegtes Objekt benutzt, ist halt selbst schuld.
    Wird es in eine Art "default" Status gesetzt muss das Handle von der Klasse geprüft werden. Man verliert also die Sicherheit, dass ein Objekt der Klasse immer nur mit gültigem Handle existieren kann.

    Wie seht ihr das? Gibt es irgendwelche Empfehlungen/Forderungen seitens des Standards?



  • Meiner Meinung nach sollte das Objekt entweder
    a) gültig oder
    b) in einem ungültigen Zustand, bei dessen Verwendung Exceptions auftreten
    sein. Auf keinen Fall sollte die verwendung eines gemoveten Objekts zu Abstürzen führen.



  • cooky451 schrieb:

    Wie seht ihr das? Gibt es irgendwelche Empfehlungen/Forderungen seitens des Standards?

    Nur dass es gültig bleibt, sonst nichts. Move ist für den Fall, dass das Objekt danach zerstört wird, gedacht. Es ist also OK, wenn das einzige, was noch erlaubt ist, der Destruktor ist.



  • Ein gemovtes Objekt ist ungültig - wie ein Zeiger der deleted wurde - einzig erlaubte Operation ist Dtor aufruf.

    Prinzipiell stellt sich die Frage aber nicht, da ein Objekt nach dem move eh nicht mehr weiter leben sollte.

    Exceptions machen hier zB auch garkeinen Sinn - denn es handelt sich ja nicht um Laufzeit Fehler, sondern Logikfehler in der Implementierung. Sowas fängt man mit assert() ab.



  • Shade Of Mine schrieb:

    Exceptions machen hier zB auch garkeinen Sinn - denn es handelt sich ja nicht um Laufzeit Fehler, sondern Logikfehler in der Implementierung. Sowas fängt man mit assert() ab.

    Deswegen gibt es auch std::logic_error und Konsorten. :p



  • Bashar schrieb:

    Es ist also OK, wenn das einzige, was noch erlaubt ist, der Destruktor ist.

    Gibt es dafür eigentlich ein Beispiel in der Standardlib? Dann wäre der Fall ja schnell geklärt.



  • cooky451 schrieb:

    Bashar schrieb:

    Es ist also OK, wenn das einzige, was noch erlaubt ist, der Destruktor ist.

    Gibt es dafür eigentlich ein Beispiel in der Standardlib? Dann wäre der Fall ja schnell geklärt.

    Nur eine Anmerkung bei der Anforderung "MoveConstructible" bzw. "MoveAssignable": "rv [rvalue, das Ausgangsobjekt] remains a valid object. Its state is unspecified."



  • Ich würde vermutlich einen nicht benutzbaren Status anstreben, an Stelle eines Status, der das Objekt zwar benutzbar belässt, wo die Benutzung aber Fehler verursacht, die vielleicht sogar noch schwer zu finden sind. Also quasi nach Möglichkeit eine Art Null-Status.



  • cooky451 schrieb:

    kann ein Objekt nachdem es "bewegt" wurde eher als ungültig oder eher als im "default" Modus angesehen werden? Diese Frage scheint mir nicht ganz unwichtig, da das Einfluss auf das Design sämtlicher Wrapperklassen um C Ressourcen hat.
    Wird ein bewegtes Objekt ungültig kann man einfach immer davon ausgehen, dass das interne Handle gültig ist. Wer dann ein bewegtes Objekt benutzt, ist halt selbst schuld.
    Wird es in eine Art "default" Status gesetzt muss das Handle von der Klasse geprüft werden. Man verliert also die Sicherheit, dass ein Objekt der Klasse immer nur mit gültigem Handle existieren kann.

    Wie seht ihr das? Gibt es irgendwelche Empfehlungen/Forderungen seitens des Standards?

    Was heißt denn "gültig"? Gültig im Sinne von "Es ist noch ein lebendes Objekt, was irgendwann mal zerstört wird" oder gültig im Sinne von "Es ist in einem Zustand, der sämtliche Operationen zulässt, die die Klasse unterstützt"?

    Das mindeste, was ein Objekt im "moved-from"-Zustand unterstützen sollte, ist, dass es noch ordentlich zerstörbar ist. Falls die Klasse die Zuweisung unterstützt, sollte es auch noch in diesem Zustand zuweisbar sein, meiner Meinung nach.

    Ich gebe Dir aber recht, dass man durch eine Move-Optimierung einigen Klassen einen neuen "Leer-Zustand" hinzufügen würde, der für viele Operationen nicht den Vorbedingungen der Operation entsprechen würde. Bei Klassen, die einen "natürlichen Leerzustand" haben, stellt sich die Frage ja nicht. Und sonst muss man wohl von Fall zu Fall entscheiden, welches Design da mehr Sinn macht.



  • Geht es denn um Klassen, die eine Form von Einzigartigkeit a la unique_ptr abstrahieren? In allen anderen Fällen sollte man doch eigentlich gar nicht mehr an das Quellobjekt der move-Operation heran kommen.
    Wenn man sich was baut, was semantisch offensichlich falsch ist, würde ich eine Assertion auslösen.

    movable_type obj;
    movable_type obj2(move(obj));
    obj.crash() //warum hier lügen, mit pseudobenutzbaren Objekten?
    


  • krümelkacker schrieb:

    Das mindeste, was ein Objekt im "moved-from"-Zustand unterstützen sollte, ist, dass es noch ordentlich zerstörbar ist. Falls die Klasse die Zuweisung unterstützt, sollte es auch noch in diesem Zustand zuweisbar sein, meiner Meinung nach.

    Ich würde auch erwarten, dass man auch noch ein anderes Objekt hinein moven kann. Sonst ist es ja blöd mit std::swap.



  • otze schrieb:

    Ich würde auch erwarten, dass man auch noch ein anderes Objekt hinein moven kann. Sonst ist es ja blöd mit std::swap.

    Vom Gefühl her gefällt mir swap über move zu implementieren nicht.



  • Shade Of Mine schrieb:

    Vom Gefühl her gefällt mir swap über move zu implementieren nicht.

    Ich empfinde es als gute Idee. Von der Bedeutung her ist swap nichts anderes als "tausche die Inhalte der beiden Objekte". Semantisch ist das ein move.

    gnu stdc++ 4.6.2 stimmt mir zu

    template<typename _Tp>
    inline void
    swap(_Tp& __a, _Tp& __b)
    {
    
      _Tp __tmp = _GLIBCXX_MOVE(__a);
      __a = _GLIBCXX_MOVE(__b);
      __b = _GLIBCXX_MOVE(__tmp);
    }
    

Anmelden zum Antworten