Для реализации подсчета ссылок мы используем IUnknown
-подобный интерфейс и класс шаблона интеллектуального указателя. Интерфейс имеет реализацию для всех методов подсчета ссылок, включая Release()
:
void IUnknownLike::Release()
{
if( --refCount == 0 ) {
delete this;
}
}
В классе шаблонов интеллектуальных указателей есть конструктор копирования и оператор присваивания, которые принимают необработанные указатели. Таким образом, пользователи могут делать следующее:
class Class : public IUnknownLike {
};
void someFunction( CSmartPointer<Class> object ); //whatever function
Class object;
someFunction( &object );
и программа работает с неопределенным поведением - объект создается с нулевым счетчиком ссылок, умный указатель создается и возвращает его в единицу, затем функция возвращается, умный указатель уничтожается, вызывает Release()
, что приводит к delete
выделенной в стеке переменной.
Пользователи также могут выполнять следующие действия:
struct COuter {
//whatever else;
Class inner;// IUnknownLike descendant
};
COuter object;
somefunction( &object.Inner );
и снова объект, не созданный с помощью new
, равен delete
d. Неопределенное поведение в лучшем виде.
Есть ли способ изменить интерфейс IUnknownLike
, чтобы пользователь был вынужден использовать new
для создания всех объектов, производных от IUnknownLike
- как производных, так и косвенных производных (с классами между наиболее производными и база)?