Самоудаляющиеся объекты
От: Nikopol  
Дата: 12.01.05 10:43
Оценка:
Здравствуйте.

Сразу оговорюсь, использование стороннего кода, даже свободно распространяемого,
невозможно.
Это ограничение написано в техзадании на проект.

Для уменьшения количества проблем, связаных с неудалёнными объектами,
написал простенький базовый класс, подсчитывающий количество ссылок на объекты.

class CSelfDeleting
{
public:
    CSelfDeleting() : m_RefCounter(1) {}
    virtual ~CSelfDeleting() {}
    virtual unsigned long AddRef() const
    {
        ++m_RefCounter;
        return m_RefCounter;
    }
    virtual unsigned long Release() const
    {
        --m_RefCounter;
        if( m_RefCounter == 0 )
            delete this;
        return m_RefCounter;
    }
protected:
    unsigned long GetRefCount()
    {
        return m_RefCounter;
    }
private:
    mutable unsigned long m_RefCounter;
};

template<class T>
class CObjectHolderCounting // T - должен быть наследником CSelfDeleting
{
public:
    // конструкторы, деструктор, операторы присваивания
private:
    T* m_pObject;
};


Повсюду в коде обычные указатели заменяются на эти, хммм.., "умные"

Основная идея — запретить удаление объектов посредством delete.
Re: Самоудаляющиеся объекты
От: Nikopol  
Дата: 12.01.05 10:49
Оценка:
Здравствуйте.

Сразу оговорюсь, использование стороннего кода, даже свободно распространяемого,
невозможно.
Это ограничение написано в техзадании на проект.

Для уменьшения количества проблем, связаных с неудалёнными объектами,
написал простенький базовый класс, подсчитывающий количество ссылок на объекты.

class CSelfDeleting
{
public:
    CSelfDeleting() : m_RefCounter(1) {}
    virtual ~CSelfDeleting() {}
    virtual unsigned long AddRef() const
    {
        ++m_RefCounter;
        return m_RefCounter;
    }
    virtual unsigned long Release() const
    {
        --m_RefCounter;
        if( m_RefCounter == 0 )
            delete this;
        return m_RefCounter;
    }
protected:
    unsigned long GetRefCount()
    {
        return m_RefCounter;
    }
private:
    mutable unsigned long m_RefCounter;
};

template<class T>
class CObjectHolderCounting // T - должен быть наследником CSelfDeleting
{
public:
    // конструкторы, деструктор, операторы присваивания
private:
    T* m_pObject;
};


Повсюду в коде обычные указатели заменяются на эти, хммм.., "умные"

Проблема в том, что всё равно можно удалить класс-наследник CSelfDeleting с помощью тривиального delete.
class CMyClass : public CSelfDeleting
{
// blah-blah
};
CMyClass* pObject = new CMyClass;
delete pObject;


Основная идея — запретить удаление объектов посредством delete.

Как бы так сделать, чтобы можно было манипулировать объектами только с помощью "умных" указателей,
но не удалять их с помощью delete.
Желательно, чтобы такие попытки отсекались самим компилятором.
Re[2]: Самоудаляющиеся объекты
От: Кодёнок  
Дата: 12.01.05 10:54
Оценка:
Сделать деструктор класса CSelfDeleting protected или private.
Re[3]: Самоудаляющиеся объекты
От: Nikopol  
Дата: 12.01.05 11:02
Оценка:
Здравствуйте, Кодёнок, Вы писали:


Кё>Сделать деструктор класса CSelfDeleting protected или private.


Пробовал

Если делать деструктор защищённым, то это ровным счётом ничего не меняет.
Компилятор это проглатывает.

Если сделать приватным, то тогда компилятор ругается на попытки объявить деструкторы у наследников.

Может это VC глючит просто ?
Re: Самоудаляющиеся объекты
От: Кодт Россия  
Дата: 12.01.05 11:04
Оценка:
Здравствуйте, Nikopol, Вы писали:

N>Сразу оговорюсь, использование стороннего кода, даже свободно распространяемого,

N>невозможно.
N>Это ограничение написано в техзадании на проект.

Используй приём "Я тут вашу полечку на русский язык перепёр"
Возьми за образец boost::intrusive_ptr.

N>Основная идея — запретить удаление объектов посредством delete.


Если повсеместно отказаться от голых указателей на объекты, а у умных указателей запретить оголение — то просто не к чему будет применять delete.
void foo(intrusive_ptr<X> px)
{
  cout << *px; // разыменование доступно
  if(!px) {} // проверка на NULL доступна
  px->y(); // доступ к членам есть

  delete px; // по пальцам от компилятора!!!
  X* p = px; // по пальцам от компилятора!!!
  // хак
  p = &*px;
  p = (px.operator->());

  px = intrusive_ptr<X>(); // обнуление
}
Перекуём баги на фичи!
Re[4]: Самоудаляющиеся объекты
От: Кодт Россия  
Дата: 12.01.05 11:28
Оценка:
Здравствуйте, Nikopol, Вы писали:

N>Если делать деструктор защищённым, то это ровным счётом ничего не меняет.

N>Компилятор это проглатывает.
N>Если сделать приватным, то тогда компилятор ругается на попытки объявить деструкторы у наследников.

Разумеется. И это не глюки.
Просто, если у наследника деструктор не определён явно, то его определяет компилятор, причём публичным. И тут — лишь бы деструктор базы был доступен наследнику.
class B1
{
  ~B1() {} // недоступен потомкам
};
class D11 : public B1
{
  // деструктор не определён явно, и если его не вызывают (скалярно или по delete), то не определён вообще
  // объект невозможно разрушить
};
class D12 : public B1
{
  ~D12() {} // ошибка: деструктор предка недоступен
};
void foo1()
{
  D11 d; // ошибка: требуется деструктор
  D11* pd = new D11(); // сколько угодно
  delete pd; // ошибка: требуется деструктор
  delete (B*)pd; // ошибка: деструктор приватный; без неё был бы баг (недоразрушение потомка)
}

class B2
{
protected:
  ~B1() {} // доступно потомкам
};
class D21
{
  // неявно определённый деструктор будет публичным
};
class D22
{
protected:
  ~D22() {} // только таким способом мы прячем деструктор
};
void foo2()
{
  D21 d1; // в лучшем виде
  D22 d2; // ошибка
  D22 *p = new D22;
  delete p; // ошибка
}

class B3
{
  virtual ~B3() {} // приватный деструктор, но из-за врождённой багофичи С++ он доступен для перекрытия
};
class D31
{
  // Неявно определённый деструктор будет виртуальным и публичным.
  // Поскольку перегрузка взламывает права доступа, деструктор предка стал доступен деструктору потомка
};
class D32
{
protected:
  ~D32() {} // только таким способом мы прячем деструктор; он, разумеется, продолжает быть виртуальным
};
Перекуём баги на фичи!
Re: Самоудаляющиеся объекты
От: Виталий Россия  
Дата: 12.01.05 11:51
Оценка:
Здравствуйте, Nikopol, Вы писали:

N>Здравствуйте.


N>Сразу оговорюсь, использование стороннего кода, даже свободно распространяемого,

N>невозможно.
N>Это ограничение написано в техзадании на проект.

N>Для уменьшения количества проблем, связаных с неудалёнными объектами,

N>написал простенький базовый класс, подсчитывающий количество ссылок на объекты.

[skip]
N>Основная идея — запретить удаление объектов посредством delete.
Можно сделать вызов оператора delete неоднозначным, предусмотрев два приведения к указателю — первый это к самому типу, а второй к void *. Компилятор будт ругаться на неоднозначность, то есть обратит внимание программиста на проблемное место.
Re[2]: Самоудаляющиеся объекты
От: Кодт Россия  
Дата: 12.01.05 11:56
Оценка:
Здравствуйте, Виталий, Вы писали:

В>Можно сделать вызов оператора delete неоднозначным, предусмотрев два приведения к указателю — первый это к самому типу, а второй к void *. Компилятор будт ругаться на неоднозначность, то есть обратит внимание программиста на проблемное место.


Если уже есть указатель на объект, то никакой неоднозначности не будет.
Удалять объект (по ссылке) — и синтаксически, и семантически абсурдно.
А если делать умный указатель, то не нужно вообще делать оператора приведения к голому указателю — тогда delete не сможет зацепиться.
Перекуём баги на фичи!
Re: Самоудаляющиеся объекты
От: Nikopol  
Дата: 12.01.05 13:12
Оценка:
В итоге плюнул на всё, и поставил банальный ассерт в деструктор CSelfDeleting.
Re[2]: Самоудаляющиеся объекты
От: Lapulya  
Дата: 12.01.05 13:53
Оценка:
Здравствуйте, Nikopol, Вы писали:

N>В итоге плюнул на всё, и поставил банальный ассерт в деструктор CSelfDeleting.


Да зачем же так жестоко. Предлагали же не плохое решение. В базовом классе делаем деструктор виртуальным и помещаем его в секцию протектыд. а в производных объявляем деструктор также в защищенной секции и все! Единственное за чем теперь надо следить чтобы соблюдать выше пересисленные два условия и проблеме решена
Re[3]: Самоудаляющиеся объекты
От: Nikopol  
Дата: 12.01.05 14:30
Оценка:
Здравствуйте, Lapulya, Вы писали:

L>Здравствуйте, Nikopol, Вы писали:


N>>В итоге плюнул на всё, и поставил банальный ассерт в деструктор CSelfDeleting.


L>Да зачем же так жестоко. Предлагали же не плохое решение.

L>В базовом классе делаем деструктор виртуальным и помещаем его в секцию протектыд.
L>а в производных объявляем деструктор также в защищенной секции и все!
L>Единственное за чем теперь надо следить чтобы соблюдать выше пересисленные два условия и проблеме решена
К сожалению, с большой степенью вероятности можно предсказать, что потом кто-нибудь определит у наследника public деструктор
Re[4]: Самоудаляющиеся объекты
От: Lapulya  
Дата: 12.01.05 14:42
Оценка:
Здравствуйте, Nikopol, Вы писали:

L>>Единственное за чем теперь надо следить чтобы соблюдать выше пересисленные два условия и проблеме решена

N>К сожалению, с большой степенью вероятности можно предсказать, что потом кто-нибудь определит у наследника public деструктор

Ну что же.. надо просто это правило зафиксировать в нейминге компании и мейминге проекта (не нужное вычеркнуть). А за не соблюдение нейминга отрывать руки и ноги (ну можно наказать примерно). Кстати при этом не кто не запрещет выбрасывать ассерт!
Re[4]: Самоудаляющиеся объекты
От: Кодт Россия  
Дата: 12.01.05 14:50
Оценка:
Здравствуйте, Nikopol, Вы писали:

N>К сожалению, с большой степенью вероятности можно предсказать, что потом кто-нибудь определит у наследника public деструктор


Объявляем тотальный запрет на голые указатели и на инструкцию delete.
Последнее — элементарно проверяется поиском по исходникам.

В случае умных указателей нас совершенно не волнует, публичный там деструктор или нет.
Перекуём баги на фичи!
Re: Самоудаляющиеся объекты
От: leper Россия  
Дата: 12.01.05 15:25
Оценка: 2 (2) +1
Здравствуйте, Nikopol, Вы писали:

N>Здравствуйте.


N>[ccode]

N> virtual unsigned long Release() const
N> {
N> --m_RefCounter;
N> if( m_RefCounter == 0 )
N> delete this; // (1)
N> return m_RefCounter;
N> }

Мои 5 копеек. Доступ к m_RefCounter после выполнения (1) к ничему хорошему не приведет.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Think for yourself. Question authory.
Re[2]: Самоудаляющиеся объекты
От: MaximE Великобритания  
Дата: 12.01.05 16:17
Оценка:
leper wrote:

> Здравствуйте, Nikopol, Вы писали:

>
> N>Здравствуйте.
>
> N>[ccode]
> N> virtual unsigned long Release() const
> N> {
> N> --m_RefCounter;
> N> if( m_RefCounter == 0 )
> N> delete this; // (1)
> N> return m_RefCounter;
> N> }
>
> Мои 5 копеек. Доступ к m_RefCounter после выполнения (1) к ничему хорошему не приведет.

100%

У меня был такой код. Был и access violation

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[3]: Самоудаляющиеся объекты
От: McSeem2 США http://www.antigrain.com
Дата: 12.01.05 17:13
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>100%


ME>У меня был такой код. Был и access violation


На самом деле, это очень типичный случай трудноуловимой ошибки. На практике, на большинстве платформ будет работать без проблем. А потом где-нибудь неожиданно выстрелит — и ищи-свищи.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[4]: Самоудаляющиеся объекты
От: MaximE Великобритания  
Дата: 12.01.05 17:36
Оценка:
McSeem2 wrote:

> Здравствуйте, MaximE, Вы писали:

>
> ME>100%
>
> ME>У меня был такой код. Был и access violation
>
> На самом деле, это очень типичный случай трудноуловимой ошибки. На практике, на большинстве платформ будет работать без проблем. А потом где-нибудь неожиданно выстрелит — и ищи-свищи.

Да, такую багу дико сложно отловить. Мне просто повезло.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re: Самоудаляющиеся объекты
От: jazzer Россия Skype: enerjazzer
Дата: 12.01.05 20:57
Оценка: +1
Здравствуйте, Nikopol, Вы писали:

N>Здравствуйте.


N>Сразу оговорюсь, использование стороннего кода, даже свободно распространяемого,

N>невозможно.
N>Это ограничение написано в техзадании на проект.

А как насчет копирования и переименования "стороннего кода, даже свободно распространяемого"?

уж лучше использовать отработанные решения копи-пейстом, чем писать свои велосипеды, которые в своем лучшем воплощении будут такими же, как внутренности того самого "стороннего кода, даже свободно распространяемого"
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Самоудаляющиеся объекты
От: Nikopol  
Дата: 13.01.05 07:41
Оценка:
Здравствуйте, leper, Вы писали:

N>> virtual unsigned long Release() const

N>> {
N>> --m_RefCounter;
N>> if( m_RefCounter == 0 )
N>> delete this; // (1)
N>> return m_RefCounter;
N>> }

L>Мои 5 копеек. Доступ к m_RefCounter после выполнения (1) к ничему хорошему не приведет.


Ой, блин....
Спасибо большое
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.