Удаление объекта с приватным деструктором - PullRequest
9 голосов
/ 23 октября 2009

Как это возможно, что разрешено удалять объект с закрытым деструктором в следующем коде? Я сократил реальную программу до следующего примера, но она все еще компилируется и работает.

class SomeClass;

int main(int argc, char *argv[])
{
  SomeClass* boo = 0; // in real program it will be valid pointer
  delete boo; // how it can work?

  return -1;
}

class SomeClass
{
private:
  ~SomeClass() {}; // ! private destructor !
};

Ответы [ 3 ]

15 голосов
/ 23 октября 2009

Вы пытаетесь удалить объект с неполным типом класса. Стандарт C ++ говорит, что в этом случае вы получите неопределенное поведение (5.3.5 / 5):

Если удаляемый объект имеет неполный тип класса в точке удаления, а полный класс имеет нетривиальный деструктор или функцию освобождения, поведение не определено.

Для выявления таких случаев вы можете использовать boost::checked_delete:

template<typename T> 
inline void checked_delete( T* p )
{
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
    (void) sizeof(type_must_be_complete);
    delete p;
}
7 голосов
/ 23 октября 2009

Этот код вызывает неопределенное поведение (UB). Это UB в C ++ к delete объекту неполного типа, имеющему нетривиальный деструктор. И в вашем коде тип SomeClass является неполным в точке delete и имеет нетривиальный деструктор. Компиляторы обычно выдают предупреждение об этом, поскольку формально в C ++ это не является нарушением ограничения.

Так что, строго говоря, ваш код не "работает". Он просто компилирует и делает что-то undefined при запуске.

Компилятору просто не требуется отлавливать эту ошибку. Причина в том, что это может быть совершенно нормально, если у вашего объекта есть деструктор тривиальный . Компилятор не может знать, какой тип деструктора будет в конечном итоге иметь этот тип, поэтому он не может точно сказать, является ли это ошибкой.

4 голосов
/ 23 октября 2009

Поскольку тип SomeClass не полностью объявлен при вызове operator delete.

Удаление такого указателя является неопределенным поведением, но на практике большинство компиляторов просто освобождают память (если указатель был не равен NULL) и не вызывают деструктор.

Например, g ++ предупредит вас об этой проблеме:

foo.cpp: In function 'int main(int, char**)':
foo.cpp:6: warning: possible problem detected in invocation of delete operator:
foo.cpp:5: warning: 'boo' has incomplete type
foo.cpp:1: warning: forward declaration of 'struct SomeClass'
foo.cpp:6: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
...