Ответ 1
Это один случай, который должен знать каждый программист на С++:
#include <stdio.h>
class EmbeddedObject {
private:
char *pBytes;
public:
EmbeddedObject() {
pBytes = new char[1000];
}
~EmbeddedObject() {
printf("EmbeddedObject::~EmbeddedObject()\n");
delete [] pBytes;
}
};
class Base {
public:
~Base(){
printf("Base::~Base()\n");
}
};
class Derived : public Base {
private:
EmbeddedObject emb;
public:
~Derived() {
printf("Derived::~Derived()\n");
}
};
int main (int argc, const char * argv[])
{
Derived *pd = new Derived();
// later for some good reason, point to it using Base pointer
Base* pb = pd;
delete pb;
}
~Base()
будет вызываться, но ~Derived()
не будет. Это означает, что код в ~Derived()
не выполняется. Возможно, что-то важное. Также он должен был автоматически вызываться деструктор EmbeddedObject
, но это не так. Поэтому EmbeddedObject
не получает возможности освобождать свои динамически распределенные данные. Это вызывает утечку памяти.
Решение, сделайте деструктор в классе Base
virtual
:
class Base {
public:
virtual ~Base() {
}
};
Приведение этого изменения в указанную выше программу означает, что все деструкторы будут вызываться в этом другом: Derived::~Derived()
, EmbeddedObject::~EmbeddedObject()
, Base::~Base()
Прочитайте деструкторы в целом. Такие проблемы, скорее всего, будут для вас чем-то серьезным, чем другие сценарии, которые вы упомянули. Например, в случае отключения питания все ставки для безопасной очистки обычно отключены!
В С++ у нас есть хороший контроль над выполнением вызова деструкторов в том порядке, в котором мы хотим, чтобы они произошли, что является хорошей новостью. Однако в программах, которые вы пишете, существует вероятность того, что ваши объекты будут пропущены, а не удалены вообще, если вы недостаточно осторожны.