2009-12-10 13 views
9

Va bene (e legale) per eliminare un puntatore che è stata passata come argomento di funzione come questa:Utilizzando delete su puntatori passati come argomenti della funzione

#include<iostream> 

class test_class{ 
public: 
    test_class():h(9){} 
    int h; 
    ~test_class(){std::cout<<"deleted";} 
}; 

void delete_test(test_class* pointer_2){ 
    delete pointer_2; 
} 

int main(){ 
    test_class* pointer_1; 

    while(true){ 
     pointer_1 = new test_class; 

     //std::cout<<pointer_1->h; 

     delete_test(pointer_1); 
    } 
} 

Questo compila bene ora, ma voglio solo per essere sicuro che sarà sempre così.

risposta

11

Compilerà sempre senza errori.

Se è una buona cosa passare un puntatore in una funzione ed eliminarlo in quella funzione è potenzialmente un'altra storia, a seconda delle specifiche del programma.

L'idea principale che è necessario considerare è quella di "proprietà" dei dati puntati. Quando si passa quel puntatore, la funzione chiamante ha la proprietà dei dati che vengono passati? cioè è nell'unico luogo dal quale si può fare riferimento a questi dati? Stai rinunciando alla proprietà dei dati puntati, senza alcuna possibilità che la funzione chiamante possa mai fare nuovamente riferimento ai dati? Se è così, allora devi cancellarlo.

Se la funzione di chiamata può fare nuovamente riferimento ai dati, non è necessario eliminarli.

Se ci sono altri riferimenti ai dati attraverso varie strutture di dati, non è sicuro cancellare questi dati se non si dispone di una disciplina in vigore nel codice per garantire che non si farà mai più riferimento ai dati da tali luoghi. Questo è difficile da fare ed è la fonte di molti bug di programmazione.

C++ tr1's shared_ptr < > è un puntatore intelligente che aiuta in questo tipo di situazioni: gestisce questo concetto di proprietà mantenendo un conteggio dei riferimenti che tiene traccia del numero di riferimenti ai dati. Se il conteggio dei riferimenti è 1, allora c'è 1 chiaro proprietario. Se il numero di riferimenti è maggiore di 1, la proprietà viene condivisa. Se il conteggio dei riferimenti è 0, non ci sono più riferimenti ai dati e shared_ptr < > lo eliminerà quando viene chiamato il distruttore < > shared_ptr.

+0

Quello che ho sempre trovato sorprendente è che l'eliminazione del puntatore è legale anche se è 'const'. –

2

Sì, questo è perfettamente legale. È possibile delete un puntatore da qualsiasi luogo, purché punti a qualche oggetto allocato sull'heap (o sia uguale a 0).

Se il chiamante si aspetta che il proprio oggetto venga cancellato dalla funzione, questa è un'altra domanda.

7

Sì, questo è valido.

Questo è comunemente fatto in C (con malloc e libero invece di nuovo ed elimina, ovviamente). In C++, è generalmente preferibile utilizzare altri idiomi di gestione della memoria come RAII, se possibile.

6

Sì, è legale in C++, ma farlo non è generalmente considerato una buona pratica. È sempre meglio per la classe che ha eseguito new a delete lo stesso.

+0

Non vedo una classe "che esegue un nuovo" in un punto qualsiasi del codice specificato. Probabilmente intendevi "blocco" invece di "classe", ma non è sempre possibile o utile. –

+0

Ma quella classe potrebbe eseguire la cancellazione utilizzando una funzione che accetta un puntatore come parametro. –

0

È perfettamente legale farlo. È necessario assicurarsi che il puntatore non venga utilizzato nel chiamante dopo quel punto. In generale, il nome della funzione che esegue l'eliminazione dovrebbe indicare che ciò che sta accadendo (ad es. Contiene cancella, rilascia, libera, ecc.). Un altro potenziale problema è assicurarsi che i dati puntati siano stati allocati con nuovi e non nuovi [].

1

Questo è completamente legale, anche se in tal caso è probabilmente meglio gestire la proprietà della memoria con qualcosa come boost::shared_ptr.

0

È valido e può essere molto utile quando si scrive un metodo di pulizia per l'oggetto, anche se 9/10 volte si vorrebbe inserire la logica di pulizia nel distruttore.

Una buona ragione per scrivere una pulizia separata sarebbe se si desidera mantenere l'oggetto "vivo" ma non utilizzato per un po ', magari in un array o pool di oggetti che si estraggono occasionalmente quando è necessario uno nuovo senza volere il sovraccarico del costruttore.

Se è necessario passare dei puntatori, è necessario verificare che non siano nulli per evitare comportamenti non definiti.

Problemi correlati