1. Паттерн "самоубийца". Объект создаётся исключительно в куче с помощью фабричного метода, управление временем жизни — через addref/release, причём release при достижении 0 в счётчике ссылок делает delete this.
2. Использование в нестатических невиртуальных методах проверки на this == NULL с возвратом некого значения по умолчанию.
Пример:
template<class TValue>
struct node
{
typedef TValue value_type;
/// create new nodestatic const node* create(const value_type& value, const node* next = 0)
{
return new node(value, next ? next->addref() : 0);
}
/// increases reference counterconst node* addref() const
{
if (!this)
return 0;
++_refcount;
return this;
}
/// decreases reference counter and frees node if necessaryvoid release() const
{
if (!this)
return;
--_refcount;
if (!_refcount)
delete this; /// no other node referencers, can be deleted
}
const node* tail() const
{
if (!this)
return 0;
return _next;
}
const value_type& value() const
{
if (!this)
throw std::logic_error("Cannot access structure via null pointer");
return _value;
}
size_t length() const
{
if (!this)
return 0;
return 1 + _tail->length();
}
private:
value_type _value; /// node's valueconst node* _next; /// next node in chainmutable size_t _refcount; /// quantity of node referencers
node(const value_type& value, const node* next)
: _value(value), _next(next)
{ }
~node()
{
_next->release();
}
};
Насколько допустимо применять подобные приёмы? Особенно (this == 0)
Здравствуйте, Alexander G, Вы писали:
AG>... но с виртуальными методами или сложным наследованием всё равно работать не будет.
Виртуальные методы или сложное наследование не предполагается. Приведённая структура живёт как private внутри класса, никак не наследуется.
Просто это позволяет в других местах сократить код проверок на != NULL.
Это можно увидеть на примере фабричного метода (в первом посте избыточный вариант):
static const node* create(const value_type& value, const node* next = 0)
{
return new node(value, next->addref());
}
Как видно, если проверка на !this корректна в случае невиртуальных методов одиночного класса, для null-хвоста мы автоматически вернём из addref нулевой указатель и создадим цепочку из одного узла с пустым хвостом.
P.S: очень интересно Ваше мнение по поводу идиомы с самоуничтожающимся объектом.
Мишень-сан wrote:
> P.S: очень интересно Ваше мнение по поводу идиомы с самоуничтожающимся > объектом.
Вместо того, чтобы писать addref/release лучше иметь handler. Т.е. объект, который в конструкторе берёт node и делает ему addref. А в деструкторе делает release. Ещё имеет метод detach, который возвращает указатель, отсоединяясь от объекта.
Здравствуйте, Мишень-сан, Вы писали:
МС>Здравствуйте, Alexander G, Вы писали:
AG>>... но с виртуальными методами или сложным наследованием всё равно работать не будет.
МС>Виртуальные методы или сложное наследование не предполагается. Приведённая структура живёт как private внутри класса, никак не наследуется. МС>Просто это позволяет в других местах сократить код проверок на != NULL. МС>Это можно увидеть на примере фабричного метода (в первом посте избыточный вариант): МС>
У себя сделал то же с методом clone, добавлен checked_clone.
МС>P.S: очень интересно Ваше мнение по поводу идиомы с самоуничтожающимся объектом.
Ничего особо плохого в этом нет.
Хотя можно избежать и удалять из самих сматрпоитеров. т.е. к boost::intrusive_ptr такие intrusive_ptr_add_ref/intrusive_ptr_release, которые сами модифицируют счечики и удаляют объект, а не делегируют методам объекта.