Essa é uma pergunta antiga, respondida, mas o @Alexandre perguntou "Por que alguém iria querer fazer isso?", E pensei em fornecer um exemplo de uso que estou considerando esta tarde.
Código legado. Usa ponteiros nus Obj * obj com um objeto de exclusão no final.
Infelizmente, às vezes, não muitas vezes, preciso manter o objeto vivo por mais tempo.
Estou pensando em torná-lo um ponteiro inteligente contado como referência. Mas haveria muito código para alterar, se eu fosse usar em ref_cnt_ptr<Obj>
qualquer lugar. E se você misturar Obj * nu e ref_cnt_ptr, poderá excluir o objeto implicitamente quando o último ref_cnt_ptr desaparecer, mesmo que o Obj * ainda esteja vivo.
Então, eu estou pensando em criar um explícito_delete_ref_cnt_ptr. Ou seja, um ponteiro contado de referência em que a exclusão é feita apenas em uma rotina de exclusão explícita. Usá-lo no local em que o código existente conhece a vida útil do objeto, bem como no meu novo código que mantém o objeto vivo por mais tempo.
Incrementar e decrementar a contagem de referência à medida que explícita_delete_ref_cnt_ptr é manipulada.
Mas NÃO libera quando a contagem de referência é vista como zero no destruidor explícito_delete_ref_cnt_ptr.
Liberando apenas quando a contagem de referência é zero em uma operação explícita de exclusão. Por exemplo, em 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;
}
}
};
OK, algo assim. É um pouco incomum ter um tipo de ponteiro contado por referência para não excluir automaticamente o objeto apontado no destruidor rc'ed ptr. Mas parece que isso pode tornar a mistura de ponteiros nus e ponteiros rc'ed um pouco mais segura.
Mas até agora não há necessidade de excluir isso.
Mas então me ocorreu: se o objeto apontado, o apontador, sabe que está sendo contado como referência, por exemplo, se a contagem estiver dentro do objeto (ou em alguma outra tabela), a rotina delete_if_rc0 pode ser um método do objeto de ponta, não o ponteiro (inteligente).
class Pointee {
private:
int rc;
...
public:
void delete_if_rc0() {
this->rc--;
if( this->rc == 0 ) {
delete this;
}
}
}
};
Na verdade, ele não precisa ser um método membro, mas pode ser uma função livre:
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, eu sei que o código não está certo - ele se torna menos legível se eu adicionar todos os detalhes, por isso estou deixando assim.)
delete this
criou um forte acoplamento entre a classe e o método de alocação usado para criar objetos dessa classe. Esse é um projeto de OO muito ruim, pois a coisa mais fundamental no OOP é criar classes autônomas que não sabem ou se importam com o que o chamador está fazendo. Portanto, uma classe projetada corretamente não deve saber ou se importar com como foi alocada. Se, por algum motivo, você precisar de um mecanismo tão peculiar, acho que um design melhor seria usar uma classe de wrapper em torno da classe real e deixar o wrapper lidar com a alocação.