Frage zu Lebenszeiten [Erledigt]
-
Hallo,
ich bin gerade über das Verhalten von std::move() überrascht. Ich habe damit gerechnet, dass wenn ich ein Objekt in eine Funktion hinein-move, die Lebenszeit von der aufgerufenen Funktion abhängig ist. Aber das ist nicht der Fall. Das Objekt überlebt die Lebenszeit der aufgerufenen Funktion:#include <iostream> #include <string> #include <memory> #include <map> class Person { public: explicit Person(std::string name) : name(name) { std::cout << "Instance of " << name << " created" << std::endl; } ~Person() { std::cout << "Destroy instance of " << name << std::endl; } std::string name; }; void fooStdMap(std::map<std::string, std::shared_ptr<Person>> &&hashToPerson) { std::cout << "foo()" << std::endl; if (hashToPerson.size() > 1) { std::cout << "hashToPerson.count() > 1" << std::endl; return; } } void exampleWithStdHashMap() { std::map<std::string, std::shared_ptr<Person>> hashToPerson; { std::shared_ptr<Person> p1 = std::make_shared<Person>("P1"); std::shared_ptr<Person> p2 = std::make_shared<Person>("P2"); std::shared_ptr<Person> p3 = std::make_shared<Person>("P3"); std::shared_ptr<Person> p4 = std::make_shared<Person>("P4"); hashToPerson = { { p1->name, p1 }, { p2->name, p2 }, { p3->name, p3 }, { p4->name, p4 }, }; } fooStdMap(std::move(hashToPerson)); std::cout << "After fooStdMap()" << std::endl; } int main() { exampleWithStdHashMap(); return 0; }
Führt zu folgendem Output:
Instance of P1 created Instance of P2 created Instance of P3 created Instance of P4 created foo() hashToPerson.count() > 1 After fooStdMap() Destroy instance of P4 Destroy instance of P3 Destroy instance of P2 Destroy instance of P1
Eigentlich hätte ich "After fooStdMap()" ganz am Ende erwartet. Weshalb werden die Objekt so spät zerstört?
Danke im Voraus
-
std::move
verschiebt nichts, es ändert nur den Typ, so dass es möglich wird an eine Rvalue Referenz zu binden. Es ermöglicht dadurch den Aufruf einer Funktion die dann das übergebene Objekt ändern könnte. So lange aber keine solche Funktion aufgerufen wird, ändert sich eben auch nichts. Und deinefooStdMap
Funktion ist keine solche Funktion, sie ändert ja nichts an der übergebenen Map.Wenn du möchtest dass wirklich der Map-Inhalt verschoben wird, dann musst du deine
fooStdMap
Funktion ändern:// Variante 1: void fooStdMap(std::map<std::string, std::shared_ptr<Person>> hashToPerson) { // ... } // Variante 2: void fooStdMap(std::map<std::string, std::shared_ptr<Person>>&& hashToPersonArg) { std::map<std::string, std::shared_ptr<Person>> hashToPerson(std::move(hashToPersonArg)); // ... }
Und ja, das move innerhalb der 2.
fooStdMap
Variante ist auch nötig.Und nochwas: Bei
move
ändert sich grundsätzlich nie die Lebenszeit des übergebenen Objekts. Auch in dem von mir gezeigten Code existiert die Map nach dem Aufruf vonfooStdMap
weiterhin. Bloss dass sie danach leer ist, weilfooStdMap
ihren Inhalt "konsumiert" hat. Dadurch ändert sich dann in diesem Beispiel die Lebenszeit der in der Map gespeichertenstd::string
undstd::shared_ptr
Objekte.
-
Hallo hustbaer,
danke, für deine Antwort! Das mit der Typänderung war mir zwar bewusst, aber andererseits move ich die Variable ja auf den Parameter der Funktion. Deshalb dachte ich, dass wenn die Funktion ausgeführt wurde, dass auch der Parameter out of scope geht und somit die Map und ihre Inhalte abgebaut werden.
Warum ist das nicht der Fall?Gruß,
Steffo
-
Weil Dein Funktionsparameter eine (RValue)Referenz ist.
-
Ja, jetzt verstehe ich. Wenn das keine Referenz wäre,
void fooStdMap(std::map<std::string, std::shared_ptr<Person>> hashToPersonArg);
dann funktioniert das auch wie erwartet.
Danke für die Aufklärung!