Questa è una domanda vecchia, con risposta, ma @Alexandre ha chiesto "Perché qualcuno dovrebbe voler fare questo?", E ho pensato che potrei fornire un esempio di utilizzo che sto prendendo in considerazione questo pomeriggio.
Codice legacy. Utilizza puntatori nudi Obj * obj con un obj di eliminazione alla fine.
Purtroppo a volte ho bisogno, non spesso, di mantenere in vita l'oggetto più a lungo.
Sto pensando di renderlo un riferimento contato puntatore intelligente. Ma ci sarebbe molto codice da cambiare, se dovessi usarlo ref_cnt_ptr<Obj>
ovunque. E se mischi Obj * nudo e ref_cnt_ptr, puoi ottenere l'oggetto implicitamente cancellato quando l'ultimo ref_cnt_ptr scompare, anche se Obj * è ancora vivo.
Quindi sto pensando di creare un esplicito_delete_ref_cnt_ptr. Vale a dire un puntatore conteggiato riferimento in cui l'eliminazione viene eseguita solo in una routine di eliminazione esplicita. Usandolo nel punto in cui il codice esistente conosce la durata dell'oggetto, così come nel mio nuovo codice che mantiene l'oggetto in vita più a lungo.
Incrementare e decrementare il conteggio dei riferimenti come esplicito_delete_ref_cnt_ptr vengono manipolati.
Ma NON liberare quando il conteggio dei riferimenti è pari a zero nel distruttore esplicito_delete_ref_cnt_ptr.
Liberazione solo quando si considera che il conteggio dei riferimenti è zero in un'operazione esplicita simile all'eliminazione. Ad esempio in qualcosa del tipo:
template<typename T> class explicit_delete_ref_cnt_ptr {
private:
T* ptr;
int rc;
...
public:
void delete_if_rc0() {
if( this->ptr ) {
this->rc--;
if( this->rc == 0 ) {
delete this->ptr;
}
this->ptr = 0;
}
}
};
OK, qualcosa del genere. È un po 'insolito avere un tipo di puntatore contato di riferimento che non cancella automaticamente l'oggetto puntato nel distruttore pc rc. Ma sembra che questo potrebbe rendere un po 'più sicuro il mix di puntatori nudi e puntatori RC.
Ma finora non è necessario eliminarlo.
Ma poi mi è venuto in mente: se l'oggetto indicato, la punta, sa che viene conteggiato il riferimento, ad esempio se il conteggio è all'interno dell'oggetto (o in qualche altra tabella), allora la routine delete_if_rc0 potrebbe essere un metodo del oggetto punteggiato, non il puntatore (intelligente).
class Pointee {
private:
int rc;
...
public:
void delete_if_rc0() {
this->rc--;
if( this->rc == 0 ) {
delete this;
}
}
}
};
In realtà, non è necessario che sia un metodo membro, ma potrebbe essere una funzione gratuita:
map<void*,int> keepalive_map;
template<typename T>
void delete_if_rc0(T*ptr) {
void* tptr = (void*)ptr;
if( keepalive_map[tptr] == 1 ) {
delete ptr;
}
};
(A proposito, so che il codice non è del tutto corretto - diventa meno leggibile se aggiungo tutti i dettagli, quindi lo lascio così.)
delete this
creato un accoppiamento stretto tra la classe e il metodo di allocazione usato per creare oggetti di quella classe. Questo è un progetto OO molto scadente, poiché la cosa più fondamentale in OOP è creare classi autonome che non conoscono o si preoccupano di ciò che il loro chiamante sta facendo. Pertanto, una classe progettata correttamente non dovrebbe conoscere o preoccuparsi di come è stata assegnata. Se per qualche motivo hai bisogno di un meccanismo così particolare, penso che un progetto migliore sarebbe usare una classe wrapper attorno alla classe reale e lasciare che il wrapper gestisca l'allocazione.