Question

J'ai un objet Foo, et un cas :: tenant liste std de celui-ci. Mon problème est que quand j'ajoute une nouvelle instance à la liste, il appelle d'abord la cteur mais aussi le dtor. Et puis le dtor sur une autre instance (selon le ce pointeur).

Une seule instance est ajouté à la liste, mais depuis sa dtor (avec ses parents,) est appelée, l'objet ne peut pas être utilisé comme prévu.

Heres un code simplifié pour illustrer le problème:

#include <iostream>
#include <list>

class Foo
{
public:
    Foo()
    { 
        int breakpoint = 0;
    }
    ~Foo()
    { 
        int breakpoint = 0;
    }
};

int main()
{
    std::list<Foo> li;
    li.push_back(Foo());
}
Était-ce utile?

La solution

Lorsque vous push_back () votre objet Foo, l'objet est copié aux structures de données internes, par conséquent, la dtor et l'Ctor d'une autre instance de la liste sont appelés.

Tous les types standard de conteneur STL en C ++ prennent leurs articles en valeur, en les copiant donc au besoin. Par exemple, chaque fois qu'un vecteur a besoin de se développer, il est possible que toutes les valeurs du vecteur sont copiés.

Peut-être que vous voulez stocker pointeurs au lieu des objets dans la liste. En faisant cela, seuls les pointeurs sont copiés au lieu de l'objet. Mais, en le faisant, vous devez vous assurer de supprimer les objets une fois que vous avez terminé:

for (std::list<Foo*>::iterator it = list.begin(); it != list.end(); ++it) {
    delete *it;
}
list.clear();

Vous pouvez essayer d'utiliser une sorte de classe « pointeur intelligent », par exemple des bibliothèques Boost.

Autres conseils

Vous créez ici un Foo temporaire:

li.push_back( Foo() )

copies de push_back que Foo dans ses structures de données internes. Le Foo temporaire est détruite après push_back a été exécuté, qui appellera le destructor.

Vous aurez besoin d'un bon constructeur de copie qui augmente le nombre de référence certains des membres de la classe que vous ne voulez pas détruire tôt - ou le rendre privé pour vous forcer à la solution de pointeur

.

Utilisez cet objet pour comprendre:

class Foo
{
public:
    Foo(int x): m_x(x)
    { 
    std::cout << "Constructed Object: " << m_x << ")\n";
    }
    Foo(Foo const& c): m_x(c.m_x+100)
    {
    std::cout << "Copied Object: " << m_x << ")\n";
    }
    ~Foo()
    {  
    std::cout << "Destroyed Object: " << m_x << ")\n";
    }
};

La première principale

std::list<Foo*> li;
li.push_back(Foo(1));

Ici, nous créons un objet temporaire Foo et appeler push_back (). L'objet temporaire est copié dans la liste et la fonction retourne. A l'issue de cette déclaration, l'objet temporaire est alors détruite (via le destructor). Lorsque la liste est détruite, il sera également détruire toutes les obejcts qu'il contient (Foo est un objet avec un destructor si la destruction comprend l'appel de la destructor).

Vous devriez voir somthing comme ceci:

Constructed Object: 1
Constructed Object: 101
DestroyedObject: 1
DestroyedObject: 101

Dans le second exemple, vous avez:

std::list<Foo*> li;
li.push_back(new Foo(1));

Ici, vous créez dynamiquement un objet sur le tas. Ensuite, appelez le push_back (). Ici, le pointeur est copié dans la liste (le pointeur n'a pas de constructeur / destructor) si rien ne se passe. La liste contient désormais un pointeur vers l'objet sur le tas. Lorsque la fonction ne retourne rien d'autre est fait. Lorsque la liste est détruite, il détruit (notez la différence subtile détruire et supprimer Betweens) l'objet qu'il contient (un pointeur), mais un pointeur n'a pas destructor rien ne se passe tout vous fuite de mémoire.

Vous devriez voir somthing comme ceci:

Constructed Object: 1

Qu'est-ce qui se passe réellement ici est que vous stockez un Copier de l'objet passé dans la liste, parce que vous l'envoyez par valeur plutôt que par référence. La première dtor que l'on appelle est en fait appelé l'objet que vous passez à la méthode push_back, mais une nouvelle instance avait été créée alors et il est maintenant enregistré dans la liste.

Si vous ne voulez pas une copie du Foo objet à créer, des pointeurs de magasin pour Foo dans la liste des objets au lieu des objets eux-mêmes. Bien sûr, quand le faire, vous devrez libérer correctement la mémoire sur la destruction de la liste.

Faire la liste des pointeurs au lieu de la tenue des instances résout le problème avec le destructor appelé. Mais je veux encore comprendre pourquoi il arrive.

#include <iostream>
#include <list>

class Foo
{
public:
    Foo()
    { 
        int breakpoint = 0;
    }
    ~Foo()
    { 
        int breakpoint = 0;
    }
};

int main()
{
    std::list<Foo*> li;
    li.push_back(new Foo());
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top