Я пытаюсь создать два класса, экземпляры которых создаются и удаляются вместе. Один класс является основой для другого:
class Interface;
class MyClass
{
friend class Interface;
private:
MyClass() {}
public:
static MyClass *NewInstance();
Interface *ControlPanel;
};
class Interface : public MyClass
{
friend class MyClass;
private:
Interface() {}
public:
void Control1() {cout << "control1" << endl;}
void Control2() {cout << "control2" << endl;}
void Control3() {cout << "control3" << endl;}
};
Две функции-члены, которые должны создавать и удалять экземпляры:
MyClass *MyClass::NewInstance()
{
MyClass *inst = new MyClass;
inst->ControlPanel = new Interface;
return inst;
}
void DeleteMyClassInstance(MyClass *inst)
{
delete inst->ControlPanel;
inst->ControlPanel = 0;
delete inst;
inst = 0;
}
Мне удалось связать процесс создания экземпляра с использованием функции в базовом классе (NewInstance()
) который создает экземпляры. Но функция удаления (DeleteMyClassInstance()
) не работает (то есть я все еще могу использовать оба inst1
а также inst1->ControlPanel
после вызова функции):
int main()
{
MyClass *inst1 = MyClass::NewInstance();
inst1->ControlPanel->Control1();
DeleteMyClassInstance(inst1);
inst1->ControlPanel->Control1();
return 0;
}
Но если я поместил код удаления в основную функцию, он работает отлично ( inst1->ControlPanel->Control1()
оператор, который идет после операторов удаления, не работает, и это то, что я хочу):
int main()
{
MyClass *inst1 = MyClass::NewInstance();
inst1->ControlPanel->Control1();
delete inst->ControlPanel;
inst->ControlPanel = 0;
delete inst;
inst = 0;
inst1->ControlPanel->Control1();
return 0;
}
Мой вопрос: почему помещение операторов delete непосредственно в основную функцию работает, в то время как помещение их в отдельную функцию, а использование в main — нет? Почему код в моем DeleteMyClassInstance()
функция игнорируется компилятором?
Измените функцию DeleteMyClassInstance на.
void DeleteMyClassInstance(MyClass **inst)
{
delete (*inst)->ControlPanel;
(*inst)->ControlPanel = 0;
delete (*inst);
*inst = 0;
}
Основное отличие состоит в том, что с кодом в main
функция inst=0
устанавливает переменную в main
функция к нулю. С кодом в DeleteMyInstance
, линия inst=0
только устанавливает локальную переменную в DeleteMyInstance
к нулю (бесполезно, поскольку после этого момента он не используется — включите больше предупреждений, и ваш компилятор может упомянуть об этом). Это не влияет на совершенно отдельную переменную с тем же именем в main
,
Итак, ваш код
DeleteMyClassInstance(inst1);
inst1->ControlPanel->Control1();
имеет неопределенное поведение, потому что вы пытаетесь использовать объект, который уже был удален. UB означает, что все может случиться. Если кажется, что это работает, вероятно, потому что в вашей реализации функция Control1
по-прежнему «работает» даже при вызове нулевого (или иным образом недопустимого) указателя, поскольку функция не использует this
или любые данные членов. Но на эту деталь реализации не следует полагаться.
Имейте в виду (если вы этого еще не сделали), что ваш код показывает плохой стиль C ++. Вы не должны писать специальные функции для удаления объектов, принадлежащих вашему классу, для этого и нужны деструкторы. И вам не нужно явно удалять объекты в деструкторах, для этого нужны умные указатели. И вам не следует использовать динамическое распределение, когда в этом нет необходимости, для этого предназначены автоматические переменные и члены данных. Во что бы то ни стало, один раз исправьте этот код как учебное упражнение, которое происходит за кулисами, но это должно быть сделано для того, чтобы сделать это правильно как можно скорее.