Это старый вопрос с ответом, но @Alexandre спросил: «Зачем кому-то это делать?», И я подумал, что могу привести пример использования, которое я рассматриваю сегодня днем.
Устаревший код. Использует голые указатели Obj * obj с удалением obj в конце.
К сожалению, иногда мне нужно, а не часто, поддерживать объект дольше.
Я рассматриваю вопрос об умном указателе. Но было бы много кода, чтобы изменить, если бы я должен был использовать ref_cnt_ptr<Obj>
везде. И если вы смешаете голый Obj * и ref_cnt_ptr, вы можете неявно удалить объект, когда последний ref_cnt_ptr исчезнет, даже если Obj * еще жив.
Поэтому я подумываю о создании явного_отделения_ref_cnt_ptr. Т.е. указатель с подсчетом ссылок, где удаление выполняется только в явной процедуре удаления. Я использую его в одном месте, где существующий код знает время жизни объекта, а также в моем новом коде, который поддерживает объект дольше.
Увеличение и уменьшение счетчика ссылок, как манипулируют явным
Но НЕ освобождается, когда счетчик ссылок считается равным нулю в деструкторе явной_далеты_ref_cnt_ptr.
Только освобождение, когда счетчик ссылок считается нулевым в явной операции удаления. Например, что-то вроде:
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;
}
}
};
ОК, что-то в этом роде. Немного необычно иметь указатель со счетчиком ссылок, который не удаляет автоматически объект, на который указывает указатель rc'ed ptr. Но кажется, что это может сделать смешивание обнаженных указателей и rc'ed указателей более безопасным.
Но пока нет необходимости удалять это.
Но потом мне пришло в голову: если объект, на который указывает указатель, знает, что на него подсчитывается ссылка, например, если счетчик находится внутри объекта (или в какой-то другой таблице), тогда процедура delete_if_rc0 может быть методом объект-указатель, а не (умный) указатель.
class Pointee {
private:
int rc;
...
public:
void delete_if_rc0() {
this->rc--;
if( this->rc == 0 ) {
delete this;
}
}
}
};
На самом деле, он вовсе не должен быть методом-членом, но может быть бесплатной функцией:
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;
}
};
(Кстати, я знаю, что код не совсем правильный - он становится менее читаемым, если я добавляю все детали, поэтому я оставляю это так.)
delete this
создали тесную связь между классом и методом выделения, используемым для создания объектов этого класса. Это очень плохой дизайн ОО, так как самое основное в ООП - создавать автономные классы, которые не знают или не заботятся о том, что делает их вызывающая программа. Таким образом, правильно разработанный класс не должен знать или заботиться о том, как он был распределен. Если вам по какой-то причине нужен такой своеобразный механизм, я думаю, что лучше было бы использовать класс-оболочку вокруг фактического класса и позволить обертке иметь дело с распределением.