Esta es una vieja pregunta contestada, pero @Alexandre preguntó "¿Por qué alguien querría hacer esto?", Y pensé que podría proporcionar un ejemplo de uso que estoy considerando esta tarde.
Código heredado Utiliza punteros desnudos Obj * obj con un obj de eliminación al final.
Lamentablemente, a veces necesito mantener el objeto vivo durante más tiempo.
Estoy considerando convertirlo en un puntero inteligente de referencia. Pero habría mucho código para cambiar, si tuviera que usarref_cnt_ptr<Obj>
todas partes. Y si mezcla Obj * desnudo y ref_cnt_ptr, puede eliminar el objeto implícitamente cuando desaparezca el último ref_cnt_ptr, aunque todavía haya Obj * vivo.
Así que estoy pensando en crear un explícito_delete_ref_cnt_ptr. Es decir, un puntero contado de referencia donde la eliminación solo se realiza en una rutina de eliminación explícita. Utilizándolo en el único lugar donde el código existente conoce la vida útil del objeto, así como en mi nuevo código que mantiene el objeto vivo por más tiempo.
Aumentando y decrementando el recuento de referencias a medida que se manipula explícitamente_delete_ref_cnt_ptr.
Pero NO se libera cuando el recuento de referencias se ve como cero en el destructor explicit_delete_ref_cnt_ptr.
Solo se libera cuando se considera que el recuento de referencia es cero en una operación explícita de eliminación. Por ejemplo, en algo como:
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;
}
}
};
De acuerdo, algo así. Es un poco inusual tener un tipo de puntero contado de referencia que no elimine automáticamente el objeto señalado en el destructor ptr rc'ed. Pero parece que esto podría hacer que mezclar punteros desnudos y punteros rojos sea un poco más seguro.
Pero hasta ahora no es necesario eliminar esto.
Pero entonces se me ocurrió: si el objeto apuntado, el puntero, sabe que se está contando por referencia, por ejemplo, si el recuento está dentro del objeto (o en alguna otra tabla), entonces la rutina delete_if_rc0 podría ser un método de objeto de puntero, no el puntero (inteligente).
class Pointee {
private:
int rc;
...
public:
void delete_if_rc0() {
this->rc--;
if( this->rc == 0 ) {
delete this;
}
}
}
};
En realidad, no necesita ser un método miembro, pero podría ser una función 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;
}
};
(Por cierto, sé que el código no es del todo correcto; se vuelve menos legible si agrego todos los detalles, así que lo dejo así).
delete this
ha creado un acoplamiento estrecho entre la clase y el método de asignación utilizado para crear objetos de esa clase. Ese es un diseño de OO muy pobre, ya que lo más fundamental en OOP es hacer clases autónomas que no saben o no se preocupan por lo que está haciendo la persona que llama. Por lo tanto, una clase diseñada adecuadamente no debería saber o importar cómo se asignó. Si por alguna razón necesita un mecanismo tan peculiar, creo que un mejor diseño sería usar una clase de envoltura alrededor de la clase real y dejar que la envoltura se encargue de la asignación.