Pregunta

Tengo un objeto Foo, y un std :: lista de la celebración de las instancias de la misma. Mi problema es que cuando agrego una nueva instancia de la lista, primero llama al ctor pero luego también el dtor. Y entonces el dtor en otro caso (de acuerdo con el puntero this).

A solo caso se añade a la lista, pero desde su DTOR (junto con sus padres) se llama, el objeto no puede ser utilizado como se esperaba.

Aquí está un cierto código simplificado para ilustrar el problema:

#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());
}
¿Fue útil?

Solución

Cuando push_back () el objeto de Foo, el objeto es copiado a las estructuras de datos internas de la lista, por lo tanto, el Dtor y la Ctor de otra instancia se llaman.

Todos los tipos de contenedores STL estándar en C ++ toman sus artículos por valor, por lo tanto, la copia según sea necesario. Por ejemplo, cada vez que un vector necesita para crecer, es posible que todos los valores en el vector se copian.

Tal vez usted quiere almacenar punteros en lugar de objetos de la lista. Al hacer esto, solamente los punteros se copian en lugar del objeto. Pero, al hacerlo, usted tiene que asegurarse de eliminar los objetos una vez que haya terminado:

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

Como alternativa, se puede tratar de utilizar algún tipo de 'inteligente puntero' de clase, por ejemplo, de las bibliotecas Boost.

Otros consejos

Está creando un Foo temporal aquí:

li.push_back( Foo() )

copias push_back que Foo en sus estructuras de datos internas. El Foo temporal se destruye después de push_back ha sido ejecutada, la cual llamará al destructor.

Se necesita un constructor de copia adecuada que aumenta un poco de recuento de referencia en los miembros de la clase que no quieren destruir temprano - o hacerlo privado que forzarse en la solución puntero

.

Utilice este objeto de entender:

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";
    }
};

El primer principal

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

Aquí creamos un objeto Foo temporal y llamamos push_back (). El objeto temporal se copia en la lista y devuelve la función. Al término de esta declaración, el objeto temporal se destruye a continuación (a través del destructor). Cuando la lista se destruye sino que también va a destruir todos los obejcts que contiene (Foo es un objeto con un destructor de manera destrucción incluye llamar al destructor).

Por lo que debería ver algo como esto:

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

En el segundo ejemplo tiene:

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

A continuación, se crea dinámicamente un objeto en el montón. Luego llame al push_back (). Aquí el puntero se copia en la lista (el puntero no tiene constructor / destructor) por lo que no ocurre nada más. La lista contiene ahora un puntero al objeto en el montón. Cuando la función devuelve nada más que se hace. Cuando la lista se destruye se destruye (nótese la diferencia sutil intermediarios destruir y eliminar) el objeto que contiene (un puntero), sino un puntero no tiene destructor que no ocurra nada va a ninguna pérdida de memoria.

Por lo que debería ver algo como esto:

Constructed Object: 1

Lo que realmente ocurre aquí es que se almacena una Copiar del objeto pasado en la lista, porque estás enviándolo por valor en lugar de por referencia. Así que la primera dtor que se llama se llama en realidad en el objeto se pasa al método push_back, pero una nueva instancia habían sido creados por el entonces y ahora se almacenan en la lista.

Si no desea que una copia del objeto Foo para crear, almacenar punteros a Foo objetos de la lista en lugar de los objetos mismos. Por supuesto, cuando lo hace, tendrá que liberar adecuadamente la memoria en la destrucción de la lista.

Hacer la lista de punteros en lugar de la celebración de los casos se resuelve el problema con el destructor se llama. Pero todavía quiero entender por qué sucede.

#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());
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top