C'est une vieille question à laquelle il a répondu, mais @Alexandre a demandé "Pourquoi quelqu'un voudrait-il faire cela?", Et j'ai pensé que je pourrais fournir un exemple d'utilisation que j'envisage cet après-midi.
Code hérité. Utilise des pointeurs nus Obj * obj avec un obj de suppression à la fin.
Malheureusement, j'ai besoin parfois, pas souvent, de garder l'objet en vie plus longtemps.
J'envisage d'en faire un pointeur intelligent compté par référence. Mais il y aurait beaucoup de code à changer si je devais l'utiliser ref_cnt_ptr<Obj>
partout. Et si vous mélangez Obj * et ref_cnt_ptr nus, vous pouvez supprimer l'objet implicitement lorsque le dernier ref_cnt_ptr disparaît, même si Obj * est toujours vivant.
Je pense donc à créer un explicit_delete_ref_cnt_ptr. C'est-à-dire un pointeur compté par référence où la suppression n'est effectuée que dans une routine de suppression explicite. En l'utilisant au seul endroit où le code existant connaît la durée de vie de l'objet, ainsi que dans mon nouveau code qui maintient l'objet en vie plus longtemps.
L'incrémentation et la décrémentation du nombre de références lorsque explicit_delete_ref_cnt_ptr sont manipulées.
Mais PAS de libération lorsque le nombre de références est considéré comme nul dans le destructeur explicit_delete_ref_cnt_ptr.
Libération uniquement lorsque le nombre de références est considéré comme nul dans une opération de type suppression explicite. Par exemple dans quelque chose comme:
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, quelque chose comme ça. Il est un peu inhabituel qu'un type de pointeur compté par référence ne supprime pas automatiquement l'objet pointé dans le destructeur ptr rc'ed. Mais il semble que cela puisse rendre un peu plus sûr le mélange des pointeurs nus et des pointeurs rc'ed.
Mais jusqu'à présent, pas besoin de supprimer cela.
Mais ensuite, cela m'est venu à l'esprit: si l'objet pointé, la pointee, sait qu'il est compté par référence, par exemple si le compte est à l'intérieur de l'objet (ou dans une autre table), alors la routine delete_if_rc0 pourrait être une méthode de la objet pointé, pas le pointeur (intelligent).
class Pointee {
private:
int rc;
...
public:
void delete_if_rc0() {
this->rc--;
if( this->rc == 0 ) {
delete this;
}
}
}
};
En fait, il ne doit pas du tout être une méthode membre, mais peut être une fonction libre:
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;
}
};
(BTW, je sais que le code n'est pas tout à fait correct - il devient moins lisible si j'ajoute tous les détails, donc je le laisse comme ça.)
delete this
avez créé un couplage étroit entre la classe et la méthode d'allocation utilisée pour créer des objets de cette classe. C'est une conception OO très médiocre, car la chose la plus fondamentale dans la POO est de créer des classes autonomes qui ne savent pas ce que leur appelant fait ou se soucient de lui. Ainsi, une classe correctement conçue ne devrait pas savoir ou se soucier de la façon dont elle a été allouée. Si, pour une raison quelconque, vous avez besoin d'un mécanisme aussi particulier, je pense qu'une meilleure conception serait d'utiliser une classe wrapper autour de la classe réelle et de laisser le wrapper gérer l'allocation.