Destruktor wird öfter aufgerufen als Konstruktor



  • operator void schrieb:

    [reserve]
    Dadurch erhalte ich auch mit VC7.1 nur einen Copy-Konstruktor-Aufruf. Der zweite kommt daher, dass die Größe des vectors durch push_back geändert wird.

    Lustige Implementierung. Normalerweise sollte push_back doch zuerst gucken, ob der Vektor vergrößert werden muss, und dann das neue Element konstruieren.



  • Tatsächlich! Danke für den Hinweis.

    Der zweite kommt daher, dass die Größe des vectors durch push_back geändert wird.

    Jetzt frage ich mich aber wie die anderen Compiler bzw. STL Implementationen das machen. Die müssen doch auch die Vector-Kapazität vergrößern.

    Ich dachte zuerst das die vielleicht schon Speicher vorreservieren, auch ohne das man das angibt, aber ein Aufruf von capacity() gibt beim g++ 0 zurück??



  • Langsam zweifle ich wirklich an MicroSoft. Dev-C++ und MSVC++ 6 toppen den neuen MSVC++ 7.1. 😮



  • Wenn der vector vergrößert wird, muss eh für jedes bisherige Element einmal der Copy-Konstruktor aufgerufen werden (nur für das gerade hinzugefügte eben theoretisch nicht). Ist also so gesehen kein schwerer Verlust. Der Kommentar im gepasteten Code verrät doch außerdem, warum es im VC7.1 geändert wurde: "in case _Val is in sequence", d.h. vec.push_back(vec[4]) geht dadurch garantiert. Ob ein assert() hier vielleicht angebrachter gewesen wäre, steht auf einem anderen Blatt 🙂



  • Hehe, wenn ich mich recht erinnere, wurde genau das vor kurzem in comp.lang.c++.moderated diskutiert.

    Ob ein assert() hier vielleicht angebrachter gewesen wäre, steht auf einem anderen Blatt 🙂

    Es ist doch nicht verboten, Elemente, die schon im Vektor enthalten sind, erneut einzufügen.





  • Das ist der falsche Link. Ich spreche von einer Diskussion darüber, wie push_back implementiert sein muss, damit auch Elemente des Vektors sicher erneut eingefügt werden können. resize ist hier völlig irrelevant.



  • Der Kommentar im gepasteten Code verrät doch außerdem, warum es im VC7.1 geändert wurde: "in case _Val is in sequence", d.h. vec.push_back(vec[4]) geht dadurch garantiert.

    Verstehe ich irgendwie nicht. 🙄
    Warum muss denn für den Fall einer Sequenz eine Kopie angelegt werden? (_Ty _Tmp = _Val;)



  • biz: Angenommen, capacity() == 100, size() == 100. Mit anderen Worten, der Vektor ist voll, die nächste Einfügung verursacht also eine Neuallokation. Wir führen jetzt v.push_back(v[0]) aus: An push_back wird eine const-Referenz auf das erste Element übergeben. Wenn push_back ohne Kopie implementiert ist, passiert folgendes: capacity() wird vergrößert, indem neuer Speicher herangeschafft und der alte Inhalt kopiert wird. push_back greift jetzt auf die übergebene Referenz zu, und versucht, in einem uninitialisierten Stück Speicher (v[100]) eine Kopie des referenzierten Objekts zu konstruieren. Durch das vorhergegangene Umschaufeln ist die Referenz jedoch ungültig geworden (bzw. verweist technisch gesehen in den üblichen Implementationen auf eine zerstörte Objektleiche), und das will man normalerweise nicht.
    Unter den vielen möglichen Lösungen wurde anscheinend eine gewählt, die vom übergebenen Objekt eine Sicherheitskopie anlegt. Man hätte auch die ganze Last für diesen Spezialfall auf den Benutzer der Klasse umschaufeln können. Oder testen können, ob die Referenz auf den Vektor selbst verweist.



  • Bashar schrieb:

    Es ist doch nicht verboten, Elemente, die schon im Vektor enthalten sind, erneut einzufügen.

    Hmmm, wenn man sagt, dass erst _nach_ dem vollständigen Aufruf von push_back Iteratoren und Referenzen ungültig werden, dann ist es erlaubt. Legt der Standard das fest?


Anmelden zum Antworten