2010-08-07 2 views
24

Ecco un esempio di codice che ho:Eliminazione di un oggetto in C++

void test() 
{ 
    Object1 *obj = new Object1(); 
    . 
    . 
    . 
    delete obj; 
} 

l'eseguo in Visual Studio, e si blocca alla linea con 'cancellare obj;'. Non è questo il modo normale per liberare la memoria associata ad un oggetto? Mi sono reso conto che richiama automaticamente il distruttore ... è normale?


Ecco un frammento di codice:.

if(node->isleaf()) 
    { 
     vector<string> vec = node->L; 
     vec.push_back(node->code); 
     sort(vec.begin(), vec.end()); 

     Mesh* msh = loadLeaves(vec, node->code); 

     Simplification smp(msh); 

     smp.simplifyErrorBased(errorThreshold); 

     int meshFaceCount = msh->faces.size(); 

     saveLeaves(vec, msh); 

     delete msh; 
    } 

loadleaves() è una funzione che legge una maglia da disco e crea un oggetto Mesh e lo restituisce (si pensi vec e node->code sono solo informazioni sulla file da aprire)

Devo rimuovere la linea delete msh;?

+3

consente di visualizzare l'aspetto della classe. potresti avere qualcosa di sbagliato con il tuo distruttore. – TheFuzz

+0

La funzione 'loadLeave' menzionata di seguito alloca l'oggetto sull'heap? o restituisce l'indirizzo di un locale o qualcosa del genere? ricorda, puoi solo "cancellare" ciò che sei nuovo "... –

+0

Assicurati che il distruttore non sia privato! – Vaibhav

risposta

32

Non è questo il modo normale di liberare la memoria associata a un oggetto?

Questo è un modo comune di gestire la memoria allocata dinamicamente, ma non è un buon modo per farlo. Questo tipo di codice è fragile perché non è protetto da eccezioni: se viene generata un'eccezione tra quando si crea l'oggetto e quando lo si elimina, si perderà quell'oggetto.

È molto meglio utilizzare un contenitore di puntatore intelligente, che è possibile utilizzare per ottenere la gestione delle risorse con riferimento all'ambito (è più comunemente chiamato resource acquisition is initialization o RAII).

Come esempio di gestione automatica delle risorse:

void test() 
{ 
    std::auto_ptr<Object1> obj1(new Object1); 

} // The object is automatically deleted when the scope ends. 

A seconda del caso d'uso, auto_ptr potrebbe non fornire la semantica si ha bisogno. In tal caso, puoi considerare l'utilizzo di shared_ptr.

Per quanto riguarda il motivo per cui il programma si arresta in modo anomalo quando si elimina l'oggetto, non è stato fornito codice sufficiente per consentire a chiunque di rispondere a tale domanda con certezza.

2

se si arresta in modo anomalo sulla riga delete, in qualche modo si è quasi certamente danneggiato l'heap. Avremmo bisogno di vedere più codice per diagnosticare il problema poiché l'esempio che hai presentato non ha errori.

Forse si dispone di un buffer overflow sull'heap che ha danneggiato le strutture dell'heap o anche qualcosa di semplice come un "double free" (o nel caso C++ "double delete").

Inoltre, come notato da Fuzz, si può avere anche un errore nel distruttore.

E sì, è del tutto normale e previsto per delete per invocare il distruttore, che è di fatto una delle sue due scopi (chiamata distruttore poi memoria libera).

3

questo non è il modo normale per liberare la memoria associata a un oggetto?

Sì, lo è.

Ho capito che invoca automaticamente il distruttore ... è normale?

Yes

Assicurarsi che hai fatto non double delete l'oggetto.

+1

Quindi, perché è normale? Dato che si tratta di una variabile puntatore, come si cancella questo normale automaticamente? Quello che succede è prima che elimini l'oggetto, e poi raggiungo alla riga '}' chiama di nuovo il distruttore, che causa il problema. La mia domanda è: perché chiama automaticamente il distruttore? Se è normale, allora perché le persone eliminano un oggetto in questo caso? – Nima

+1

Leggi questi: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9 e http://www.parashift.com/c++-faq-lite/freestore-mgmt.html# faq-16.9 'Quindi il distruttore Fred :: ~ Fred() * verrà * automaticamente richiamato quando si cancella ......' Mostraci il codice completo. –

6

Il codice utilizza effettivamente il modo normale di creare ed eliminare un oggetto dinamico. Sì, è perfettamente normale (e sicuramente garantito dallo standard di lingua!) Che delete chiamerà il distruttore dell'oggetto, proprio come new deve richiamare il costruttore.

Se non fossi istanziare Object1 direttamente, ma un po 'sottoclasse di ciò, mi piacerebbe ricordare che ogni classe deve essere ereditata da deve avere un virtuale distruttore (in modo che distruttore e la correttezza della sottoclasse può essere invocata in casi analoghi a questo) - ma se il tuo codice campione è effettivamente rappresentativo del tuo codice attuale, questo non può essere il tuo problema corrente - deve essere qualcos'altro, magari nel codice distruttore che non ci stai mostrando, o qualche corruzione dell'heap in il codice che non stai mostrando all'interno di quella funzione o quelli che chiama ...?

BTW, se si elimina sempre l'oggetto poco prima di uscire dalla funzione che lo istanzia, non c'è motivo di rendere dinamico quell'oggetto - basta dichiararlo come locale (classe di memoria auto, come è il default) variabile di detta funzione!

1

saveLeaves(vec,msh);
Sto assumendo prende il puntatore msh e lo inserisce all'interno di vec. Poiché msh è solo un puntatore alla memoria, se lo elimini, verrà eliminato anche all'interno del vettore.