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 deine fooStdMap 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 von fooStdMap weiterhin. Bloss dass sie danach leer ist, weil fooStdMap ihren Inhalt "konsumiert" hat. Dadurch ändert sich dann in diesem Beispiel die Lebenszeit der in der Map gespeicherten std::string und std::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! 🙂


Log in to reply