Сразу оговорюсь, использование стороннего кода, даже свободно распространяемого,
невозможно.
Это ограничение написано в техзадании на проект.
Для уменьшения количества проблем, связаных с неудалёнными объектами,
написал простенький базовый класс, подсчитывающий количество ссылок на объекты.
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.
Желательно, чтобы такие попытки отсекались самим компилятором.
Здравствуйте, 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>(); // обнуление
}
Здравствуйте, 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() {} // только таким способом мы прячем деструктор; он, разумеется, продолжает быть виртуальным
};
Здравствуйте, Nikopol, Вы писали:
N>Здравствуйте.
N>Сразу оговорюсь, использование стороннего кода, даже свободно распространяемого, N>невозможно. N>Это ограничение написано в техзадании на проект.
N>Для уменьшения количества проблем, связаных с неудалёнными объектами, N>написал простенький базовый класс, подсчитывающий количество ссылок на объекты.
[skip] N>Основная идея — запретить удаление объектов посредством delete.
Можно сделать вызов оператора delete неоднозначным, предусмотрев два приведения к указателю — первый это к самому типу, а второй к void *. Компилятор будт ругаться на неоднозначность, то есть обратит внимание программиста на проблемное место.
Здравствуйте, Виталий, Вы писали:
В>Можно сделать вызов оператора delete неоднозначным, предусмотрев два приведения к указателю — первый это к самому типу, а второй к void *. Компилятор будт ругаться на неоднозначность, то есть обратит внимание программиста на проблемное место.
Если уже есть указатель на объект, то никакой неоднозначности не будет.
Удалять объект (по ссылке) — и синтаксически, и семантически абсурдно.
А если делать умный указатель, то не нужно вообще делать оператора приведения к голому указателю — тогда delete не сможет зацепиться.
Здравствуйте, Nikopol, Вы писали:
N>В итоге плюнул на всё, и поставил банальный ассерт в деструктор CSelfDeleting.
Да зачем же так жестоко. Предлагали же не плохое решение. В базовом классе делаем деструктор виртуальным и помещаем его в секцию протектыд. а в производных объявляем деструктор также в защищенной секции и все! Единственное за чем теперь надо следить чтобы соблюдать выше пересисленные два условия и проблеме решена
Здравствуйте, Lapulya, Вы писали:
L>Здравствуйте, Nikopol, Вы писали:
N>>В итоге плюнул на всё, и поставил банальный ассерт в деструктор CSelfDeleting.
L>Да зачем же так жестоко. Предлагали же не плохое решение. L>В базовом классе делаем деструктор виртуальным и помещаем его в секцию протектыд. L>а в производных объявляем деструктор также в защищенной секции и все! L>Единственное за чем теперь надо следить чтобы соблюдать выше пересисленные два условия и проблеме решена
К сожалению, с большой степенью вероятности можно предсказать, что потом кто-нибудь определит у наследника public деструктор
Здравствуйте, Nikopol, Вы писали:
L>>Единственное за чем теперь надо следить чтобы соблюдать выше пересисленные два условия и проблеме решена N>К сожалению, с большой степенью вероятности можно предсказать, что потом кто-нибудь определит у наследника public деструктор
Ну что же.. надо просто это правило зафиксировать в нейминге компании и мейминге проекта (не нужное вычеркнуть). А за не соблюдение нейминга отрывать руки и ноги (ну можно наказать примерно). Кстати при этом не кто не запрещет выбрасывать ассерт!
Здравствуйте, Nikopol, Вы писали:
N>К сожалению, с большой степенью вероятности можно предсказать, что потом кто-нибудь определит у наследника public деструктор
Объявляем тотальный запрет на голые указатели и на инструкцию delete.
Последнее — элементарно проверяется поиском по исходникам.
В случае умных указателей нас совершенно не волнует, публичный там деструктор или нет.
Здравствуйте, MaximE, Вы писали:
ME>100%
ME>У меня был такой код. Был и access violation
На самом деле, это очень типичный случай трудноуловимой ошибки. На практике, на большинстве платформ будет работать без проблем. А потом где-нибудь неожиданно выстрелит — и ищи-свищи.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
McSeem2 wrote:
> Здравствуйте, MaximE, Вы писали: > > ME>100% > > ME>У меня был такой код. Был и access violation > > На самом деле, это очень типичный случай трудноуловимой ошибки. На практике, на большинстве платформ будет работать без проблем. А потом где-нибудь неожиданно выстрелит — и ищи-свищи.
Да, такую багу дико сложно отловить. Мне просто повезло.
Здравствуйте, Nikopol, Вы писали:
N>Здравствуйте.
N>Сразу оговорюсь, использование стороннего кода, даже свободно распространяемого, N>невозможно. N>Это ограничение написано в техзадании на проект.
А как насчет копирования и переименования "стороннего кода, даже свободно распространяемого"?
уж лучше использовать отработанные решения копи-пейстом, чем писать свои велосипеды, которые в своем лучшем воплощении будут такими же, как внутренности того самого "стороннего кода, даже свободно распространяемого"