Це старе, відповів на запитання, але @Alexandre запитав "Чому хтось хотів би це зробити?", І я подумав, що я можу навести приклад використання, який я розглядаю сьогодні вдень.
Спадковий код. Використовує голі вказівники Obj * obj із видаленням obj в кінці.
На жаль, мені потрібно часом, не часто, щоб довше зберегти живий об’єкт.
Я розглядаю, як зробити його посиланням, підрахувавши розумний покажчик. Але було б багато коду для зміни, якби я використовував ref_cnt_ptr<Obj>
всюди. І якщо ви змішуєте голий Obj * і ref_cnt_ptr, ви можете отримати об'єкт неявно видалений, коли останній ref_cnt_ptr відходить, навіть якщо Obj * ще живий.
Тому я думаю про створення явного_делето_реф_cnt_ptr. Тобто довідковий лічильний покажчик, де видалення виконується лише в явній процедурі видалення. Використовуючи його в тому місці, де існуючий код знає термін експлуатації об'єкта, а також у моєму новому коді, який довше зберігає живий об’єкт.
Збільшення та зменшення кількості відліку, як явний_delete_ref_cnt_ptr, маніпулюють.
Але НЕ звільняється, коли в деструкторі express_delete_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 покажчиків трохи безпечніше.
Але поки видаляти це не потрібно.
Але тоді мені прийшло в голову: якщо об’єкт, на який вказували, pointee, знає, що він посилається, наприклад, якщо підрахунок знаходиться всередині об'єкта (або в якійсь іншій таблиці), то рутина delete_if_rc0 може бути методом об'єкт pointee, а не (розумний) покажчик.
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
створили щільну зв'язок між класом та методом розподілу, який використовується для створення об’єктів цього класу. Це дуже поганий дизайн ОО, оскільки найосновніше в ООП - це робити автономні класи, які не знають і не цікавляться тим, що робить їхній абонент. Таким чином, правильно розроблений клас не повинен знати або дбати про те, як він був виділений. Якщо вам чомусь потрібен такий своєрідний механізм, я думаю, що кращим дизайном було б використовувати клас обгортки навколо фактичного класу, і дозволити обгортці займатися розподілом.