std::vector push_back() destruktor umgehen
-
kralo9 schrieb:
Ah nein ich habe das anders gemeint. Ich wollte wissen, welche Funktionen bei welchen Operationen aufgerufen werden. Also, welche Funktion tritt in Kraft, wenn ich ein std::move mache.
std::move löst selbst überhaupt keinen weiteren Funktionsaufruf aus. Eine Initialisierung od. Zuweisung danach führt allerdings zum Aufruf des Move-ctor bzw. move-Zuweisungsoperators (sofern diese vorhanden sind).
class MyClass : public counter_mixin { public: MyClass() : _killWhenLast(12345) { std::cout << "MyClass Constructor\n"; } MyClass(const MyClass&) = default; // ruft copy-ctor des mixins auf MyClass(MyClass&&) = default; // ruft move-ctor des mixins auf MyClass& operator=(const MyClass&) = default; // ruft copy-op des mixins auf MyClass& operator=(MyClass&&) = default; // ruft move-op des mixins auf ~MyClass() { std::cout << "MyClass Destructor\n"; if(is_unique()){ _killWhenLast = 0; } std::cout << "_killWhenLast: " << _killWhenLast << "\n"; } private: int _killWhenLast; }; int main() { MyClass m; assert(m.count() == 1); { MyClass m2; assert(m2.count() == 1); m2 = std::move(m); // ruft den move-Zuweisungsoperator auf assert(m2.count() == 1); assert(m.count() == 1); // m ist nach dem move "leer" MyClass m3(std::move(m2)); // ruft den move-ctor auf assert(m.count() == 1); assert(m2.count() == 1); assert(m3.count() == 1); } assert(m.count() == 1); }
-
Ah danke. Jetzt weiß ich den Move-Ctor und Move-Zuweiser

Mir fällt es etwas schwer zu verstehen, was eine "leere" Klasse ist, nachdem sie bewegt wurde.
Was ist m2 nachm = std::move(m2);?
Edit: Hat das doppelte Ampersand (&) eine wirkliche bedeutung oder ist das nur da, um den move zu definieren?
Edit2: Wird bei oben genanntem move der destruktor von m2 aufgerufen?
-
Mir fällt es etwas schwer zu verstehen, was eine "leere" Klasse ist, nachdem sie bewegt wurde.
Sie ist nicht leer, sondern ihre Ressourcen wurden weitergegeben. Meistens ist sie dann entweder einfach ungültig, oder ihr Status ist nicht weiter definiert, oder sie ist einfach im "Standardzustand" (also ein Container ist im "Standardzustand" leer, ohne Elemente - welchen Status der Allokator hat, hängt von anderen Sachen ab).
Edit: Hat das doppelte Ampersand (&) eine wirkliche bedeutung oder ist das nur da, um den move zu definieren?
Ja, damit qualifizierst du einen Typen um eine sog. rvalue-Referenz zu bekommen.
int a; // Ein Objekt int& a_ref = a; // Eine lvalue-Referenz auf int int&& a_rref = std::move(a); // eine rvalue-Referenz auf int. Bei Skalaren ist moven sinnlos, da diese keine Ressourcen halten.
-
lvalue und rvalue...
x = 3;x ist lvalue und 3 ist rvalue, richtig?
-
Ja, richtig! 3 ist ein Literal. Ein (normales) Literal ist immer ein rvalue.
Und x muss ein lvalue sein.
-
Haha jaa

Aber ich verstehe nicht den zusammenhang mit Klassen.
Und:
Gibt es einen Unterschied zwischen folgenden Funktionen?:void MyClass::operator=(const MyClass& other){ ... } MyClass& MyClass::operator=(const MyClass& other){ ... return [MyClass]; }Und woher weiß der Compiler, welchen operator= ich meine?
-
void MyClass::operator=(const MyClass& other) // Sollte wohl MyClass& zurückgeben { ... } MyClass& MyClass::operator=(const MyClass& other) { ... return [MyClass]; // Was ist das? Du meinst wohl *this... }Und woher weiß der Compiler, welchen operator= ich meine?
Du darfst so gar nicht überladen. Funktionen, die sich nur ihn ihrem Rückgabewert unterscheiden, können nicht überladen werden.
-
- schrieb:
void MyClass::operator=(const MyClass& other) // Sollte wohl MyClass& zurückgeben { ... } MyClass& MyClass::operator=(const MyClass& other) { ... return [MyClass]; // Was ist das? Du meinst wohl *this... }Und woher weiß der Compiler, welchen operator= ich meine?
Du darfst so gar nicht überladen. Funktionen, die sich nur ihn ihrem Rückgabewert unterscheiden, können nicht überladen werden.
Also sind beide Funktionen identisch?
[MyClass] sollte ein platzhalter für ein objekt vom typ MyClass sein...Edit: Wieso ruft das den CopyCtor auf?
MyClass m4(std::move(m2));
-
Weil kein Move-Konstruktor definiert ist.
-
kralo9 schrieb:
knivil schrieb:
Nun, ob MyClass wirklich ein ReferenceCounter ist, bezweifle ich. Die is_a-Beziehung kann schwer gerechtfertigt werden.
Da gebe ich dir Recht. Es sollte eine Has-A Beziehung sein. Ansonsten gebe ich dir kein Recht.
Has-A löst auch das Problem mit der Namensreservierung der Funktionen.
Du könntest den relativ seltenen Weg der privaten Vererbung wählen. Die drückt eine "is implemented by"-Beziehung aus. Und da du ja nicht per Basisklassenzeiger oder -referenz auf deine Objekte zugreifst brauchst du in Richtung ReferenceCounter auch keine Polymorphie haben.
Dann:
void MyClass::operator=(const MyClass& other) { // ... } MyClass& MyClass::operator=(const MyClass& other) { return *this; }Die void Methode ist nicht sehr sinnvoll, denn dadurch werden solche Konstrukte nicht mehr möglich sein:
MyClass m1, m2, m3; m1 = m2 = m3 = MyClass(); if ( (m1 = 2*m2) == m3 ) {}Zweitens gibt es das wunderschnöde Copy&Swap Pattern:
MyClass::MyClass(MyClass const& m) { // Copy-C-Tor Implementieren } MyClass& MyClass::operator=(MyClass m) { this->swap(m); return *this; } void MyClass::swap(MyClass & other) { // swap implementieren }
-
Ich glaube die has-a Beziehung ist ganz ok. Danke dennoch für das Erwähnen der is-implemented-by beziehung.
Ich möchte nochmal die Frage stellen, ob std::move(m123) den Destruktor von m123 aufruft.
Ich zähl nochmal kurz auf:
Ctor
CopyCtor
operator=
MoveCtor
Move-operator=
(Swap-operator=)Gibt es noch was?
Neue Objekte, d.h. eine Erhöhung des Counters, entsteht nur bei den ersten 3 Möglichkeiten, richtig?
-
Nein, das ist falsch.
Neue Objekte werden bei allen 3 Konstruktoren erzeugt: Ctor,Copy-Ctor, Move-Ctor.
Die Assignment-Operatoren löschen zwar alte Ressourcen, aber erzeugen keine neuen Objekte.
Und die Swap-Methode ist eine normale Methode. Infos
Move ruft keinen Destruktor auf. Move ruft den Move Konstruktor oder Zuweisungsoperator auf. Da weisst du dann, dass du das übergebene Objekt in einen Zustand bringen kannst, der nicht mehr interessiert, da es eh nicht gebraucht wird. (Das stimmt so natürlich nicht, jedes lebendige Objekt sollte immer in einem gültigen Zustand sein. Vielleicht wäre Initial- oder Leerzustand treffender.)