Selfdestruct object и this == NULL
От: Мишень-сан  
Дата: 30.10.09 09:51
Оценка:
Доброго времени суток!

Возник вопрос по применению двух мини-паттернов.

1. Паттерн "самоубийца". Объект создаётся исключительно в куче с помощью фабричного метода, управление временем жизни — через addref/release, причём release при достижении 0 в счётчике ссылок делает delete this.
2. Использование в нестатических невиртуальных методах проверки на this == NULL с возвратом некого значения по умолчанию.
Пример:
  template<class TValue>
  struct node
  {
    typedef TValue value_type;
    /// create new node
    static const node* create(const value_type& value, const node* next = 0)
    {
      return new node(value, next ? next->addref() : 0);
    }
    /// increases reference counter
    const node* addref() const
    {
      if (!this)
        return 0;
      ++_refcount;
      return this;
    }
    /// decreases reference counter and frees node if necessary
    void 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 value
    const node*     _next;      /// next node in chain
    mutable size_t  _refcount;  /// quantity of node referencers
  
    node(const value_type& value, const node* next)
      : _value(value), _next(next)
    { }
 
    ~node()
    {
      _next->release();
    }
  };


Насколько допустимо применять подобные приёмы? Особенно (this == 0)
Re: Selfdestruct object и this == NULL
От: Alexander G Украина  
Дата: 30.10.09 10:06
Оценка:
Здравствуйте, Мишень-сан, Вы писали:

МС>Насколько допустимо применять подобные приёмы? Особенно (this == 0)


UB начинается уже при разыменовании нулевого указателя, т. при вызове p->foo при p == 0.

В MSVC есть методы вроде GetSafeHwnd, которые полагаются на такое, но с виртуальными методами или сложным наследованием всё равно работать не будет.
Русский военный корабль идёт ко дну!
Re[2]: Selfdestruct object и this == NULL
От: Мишень-сан  
Дата: 30.10.09 10:36
Оценка:
Здравствуйте, 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: очень интересно Ваше мнение по поводу идиомы с самоуничтожающимся объектом.
Re[3]: Selfdestruct object и this == NULL
От: . Великобритания  
Дата: 30.10.09 11:32
Оценка:
Мишень-сан wrote:

> P.S: очень интересно Ваше мнение по поводу идиомы с самоуничтожающимся

> объектом.
Вместо того, чтобы писать addref/release лучше иметь handler. Т.е. объект, который в конструкторе берёт node и делает ему addref. А в деструкторе делает release. Ещё имеет метод detach, который возвращает указатель, отсоединяясь от объекта.
struct node_handler
{
  node *n;
  node_handler(node *n)
    : n(n)
  {
    if(n) n->addref();
  }
  ~node_handler()
  {
    if(n) n->release();
  }
  node *detach()
  {
    node *tmp = n;
    n = NULL;
    return tmp;
  }
}
...
return new node(value, node_handler(next)->detach());
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[3]: Selfdestruct object и this == NULL
От: Alexander G Украина  
Дата: 30.10.09 11:34
Оценка:
Здравствуйте, Мишень-сан, Вы писали:

МС>Здравствуйте, Alexander G, Вы писали:


AG>>... но с виртуальными методами или сложным наследованием всё равно работать не будет.


МС>Виртуальные методы или сложное наследование не предполагается. Приведённая структура живёт как private внутри класса, никак не наследуется.

МС>Просто это позволяет в других местах сократить код проверок на != NULL.
МС>Это можно увидеть на примере фабричного метода (в первом посте избыточный вариант):
МС>
МС>    static const node* create(const value_type& value, const node* next = 0)
МС>    {
МС>      return new node(value, next->addref());
МС>    }
МС>


Можно чделать checked_addref свободной функцией или статическим методом. После чего:
    friend const node* checked_addref(const node* src) 
    {
      return src ? src->addref() : 0;
    }
    static const node* create(const value_type& value, const node* next = 0)
    {
      return new node(value, checked_addref(next));
    }


У себя сделал то же с методом clone, добавлен checked_clone.

МС>P.S: очень интересно Ваше мнение по поводу идиомы с самоуничтожающимся объектом.


Ничего особо плохого в этом нет.
Хотя можно избежать и удалять из самих сматрпоитеров. т.е. к boost::intrusive_ptr такие intrusive_ptr_add_ref/intrusive_ptr_release, которые сами модифицируют счечики и удаляют объект, а не делегируют методам объекта.
Русский военный корабль идёт ко дну!
Re: Selfdestruct object и this == NULL
От: Юрий Жмеренецкий ICQ 380412032
Дата: 01.11.09 12:41
Оценка:
Здравствуйте, Мишень-сан, Вы писали:

МС>Насколько допустимо применять подобные приёмы? Особенно (this == 0)


Наличие такой проверки — это констатация наличия UB. Поэтому вопрос трансформируется в другой — насколько допустимо наличие UB в программе.
Re[2]: Selfdestruct object и this == NULL
От: Мишень-сан  
Дата: 02.11.09 08:56
Оценка:
Всем большое спасибо за ответы. Переделал под статик методы, так что ни this==0, ни selfdestruct не используются.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.