Domanda

Ho un oggetto Foo, e uno std :: list tenendo istanze di esso. Il mio problema è che quando aggiungo una nuova istanza alla lista, prima chiama il ctor, ma poi anche il dtor. E poi il dtor su un'altra istanza (secondo il questo puntatore).

Una singola istanza viene aggiunto alla lista, ma fin dalla sua dtor (insieme con i suoi genitori) è chiamato, l'oggetto cant essere utilizzato come previsto.

Ecco un po 'di codice semplificato per illustrare il 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());
}
È stato utile?

Soluzione

Quando si push_back () l'oggetto Foo, l'oggetto è copiato per le strutture dati interne della lista, quindi il dtor e il ctor di un'altra istanza sono chiamati.

Tutti i tipi di contenitori STL standard in C ++ prendono i loro oggetti per valore, quindi la copia, se necessario. Ad esempio, ogni volta che un vettore ha bisogno di crescere, è possibile che tutti i valori nel vettore vengono copiati.

Forse si desidera memorizzare puntatori al posto di oggetti nella lista. Così facendo, solo i puntatori vengono copiati anziché l'oggetto. Ma, così facendo, si deve fare in modo di eliminare gli oggetti una volta che hai finito:

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

In alternativa, si può provare ad utilizzare una sorta di 'puntatore intelligente' di classe, ad esempio, dalle librerie Boost.

Altri suggerimenti

Si sta creando una Foo temporanea qui:

li.push_back( Foo() )

copie push_back che Foo nelle sue strutture dati interne. La Foo temporaneo viene distrutto dopo push_back è stato eseguito, che chiamerà il distruttore.

È necessario un costruttore di copia corretta che aumenta un po 'di conteggio dei riferimenti sui membri della classe che non si desidera distruggere presto - o renderlo privato a sforzatevi sulla soluzione puntatore

.

Utilizzare questo oggetto per capire:

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 prima principale

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

Qui creiamo un oggetto Foo temporanea e chiamiamo push_back (). L'oggetto temporaneo viene copiato nella lista e restituisce la funzione. Al termine di questa dichiarazione l'oggetto temporaneo viene poi distrutta (attraverso il distruttore). Quando la lista viene distrutto sarà anche distruggere tutte le obejcts in esso contenuti (Foo è un oggetto con un distruttore in modo distruzione include chiamando il distruttore).

Quindi, si dovrebbe vedere somthing come questo:

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

Nel secondo esempio si dispone di:

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

Qui si crea dinamicamente un oggetto sul mucchio. Quindi chiamare il push_back (). Qui il puntatore viene copiato nella lista (il puntatore non ha un costruttore / distruttore) in modo da non succede nient'altro. La lista contiene un puntatore all'oggetto sul mucchio. Quando la funzione restituisce niente altro è fatto. Quando la lista viene distrutta distrugge (notare la sottile differenza betweens distruggere e cancellare) l'oggetto che contiene (un puntatore), ma un puntatore non ha distruttore così non succede nulla qualsiasi si perdita di memoria.

Quindi, si dovrebbe vedere somthing come questo:

Constructed Object: 1

Quello che succede in realtà qui è che si memorizza un copia dell'oggetto passato nella lista, perché si sta inviando per valore invece che per riferimento. Quindi la prima dtor che si chiama in realtà è chiamato sull'oggetto si passa al metodo push_back, ma una nuova istanza erano stati creati da allora ed è ora memorizzato nella lista.

Se non si desidera una copia dell'oggetto Foo per essere creato, puntatori negozio di Foo oggetti nella lista al posto degli oggetti stessi. Naturalmente quando farlo si dovrà rilasciare correttamente la memoria sulla distruzione della lista.

Fare la lista indicatori della holding al posto dei casi risolve il problema con il distruttore viene chiamato. Ma ho ancora voglia di capire perché succede.

#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());
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top