Quelqu'un peut-il expliquer pourquoi le destructeur de la classe bar est appelé dans la ligne où l'objet du même type est initialisé?

    #include <memory>
    #include <iostream>

    using namespace std;

    class bar
    {
      public:
        bar() {}

        ~bar() { std::cout << "destructor called " << std::endl; }
    };

    class foo
    {
      public:
        foo(std::shared_ptr<bar> barP) {}
    };


    int main() {

        std::shared_ptr<foo> f;
        std::cout << "before init " << std::endl;
        f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
        std::cout << "after init"  << std::endl;
    }

Production:

before init 
destructor called 
after init
1
user1009285 6 mai 2020 à 04:28

3 réponses

Meilleure réponse

Cette déclaration:

f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Construit un shared_ptr temporaire qui sort du cadre à la fin de l'instruction. À ce stade, le shared_ptr s'en va, emportant bar avec lui (car aucune copie du shared_ptr ne reste en vie).

Mais si vous changez foo pour lire comme ceci:

class foo
{
  public:
    foo(std::shared_ptr<bar> barP) { m_bar = barP; }
    std::shared_ptr<bar> m_bar;
};

Ensuite, la sortie que vous obtenez correspond probablement à ce que vous attendiez, car foo conserve une copie de shared_ptr jusqu'à ce qu'il (foo) soit hors de portée et que cette copie conserve bar vivant:

before init 
after init
destructor called

Démo en direct

3
Paul Sanders 6 mai 2020 à 01:46

C'est parce que l'instance bar ne vit que pendant la durée du constructeur foo. Il est donc construit, passé dans le shared_ptr, qui est alors dans le constructeur foo. Dès que ce constructeur est terminé (même si sur la même ligne), l'expression elle-même est terminée, et ainsi le shared_ptr est terminé et détruit.

À la fin de main juste avant le cout, vous avez encore un shared_ptr à foo dans f, mais le shared_ptr sans nom à votre {{X5} } l'objet est déjà "hors de portée".

1
Kevin Anderson 6 mai 2020 à 01:39

Tout d'abord, vous ne devez pas instancier shared_ptr de cette manière, utilisez make_shared pour instancier shared_ptr. Veuillez vérifier le code modifié -

#include <memory>
#include <iostream>

using namespace std;

class bar
{
  public:
    bar() {}

    ~bar() { std::cout << "destructor called " << std::endl; }
};

class foo
{
  public:
    foo(std::shared_ptr<bar> barP) {}
};


int main() {

    std::shared_ptr<foo> f;
    std::cout << "before init " << std::endl;
    std::shared_ptr<bar> b = std::make_shared<bar>();
    f = std::make_shared<foo>(b);
    std::cout << "after init"  << std::endl;
}

La sortie du programme ci-dessus -

before init 
after init
destructor called 

Généralement, ce qui se passe avec votre code, c'est que vous passez new bar au constructeur de foo. Et personne ne détient la propriété du pointeur partagé bar. Ainsi, le nombre de références devient 0 et il est en cours de suppression, d'où l'appel du destructeur.

Pour en savoir plus : make_shared vs new

0
Naseef Ur Rahman 6 mai 2020 à 01:48