Я экспериментирую с перегрузкой оператора delete, чтобы я мог вернуть простой указатель тем, кто не хочет работать с интеллектуальными указателями, но при этом иметь возможность контролировать, когда объект удаляется.
Я определяю класс Cat, который создан с несколькими душами, имеет перегруженный оператор delete, который ничего не делает, и деструктор, который уменьшает количество душ (а также немного хвастается). Когда souls достигает 0, деструктор вызывает global :: delete, и кот умирает.
Звучит довольно просто, но работает не так, как ожидалось. Вот код:
class Cat {
public:
Cat(string n): name(n), souls(9)
{ cout << "Myaou... " << name << " is born\n"; }
~Cat();
void operator delete(void *p) { cout << "!!! operator delete called\n"; }
void report()
{ cout << name << "'s here, " << souls << " souls to spend\n"; }
friend ostream& operator<< (const ostream& o, const Cat& cat);
private:
void kill();
const string name;
int souls;
};
Cat::~Cat()
{
cout << "!!! dtor called\n";
kill();
}
void Cat::kill()
{
if (--souls)
cout << name << " is still alive! I have " << souls << " souls left.\n";
else {
cout << name << " is dying... good bye world!\n";
::delete((void*)this);
}
}
ostream& operator<< (const ostream& o, const Cat& cat)
{
return o << cat.name << "'s here, " << cat.souls << " souls to spend\n";
}
вот главное:
int main()
{
Cat *p = new Cat("Mitzi");
for (;;)
{
char c[100];
// cout << *p;
p->report();
cout << "come on, hit me!";
cin >> c;
delete p;
}
}
Я ожидаю, что цикл будет выполняться 9 раз, а затем произойдет что-то неприятное (аварийное завершение). Тем не менее, это вывод:
Myaou... Mitzi is born
Mitzi's here, 9 souls to spend
come on, hit me!c
!!! dtor called
Mitzi is still alive! I have 8 souls left.
!!! operator delete called
's here, 8 souls to spend
come on, hit me!c
!!! dtor called
is still alive! I have 7 souls left.
*** glibc detected *** /home/davidk/workspace/string_test/Debug/string_test: double free or corruption (fasttop): 0x080cd008 ***
Похоже, что после первого удаления имя элемента уничтожается, а следующее удаление вызывает сбой. Есть объяснения? Я компилирую с gcc на Linux, может быть ошибка компилятора?
Кстати, когда я использовал оператор << () как в cout << * p вместо repotr (), это также было странно: он входил в бесконечный цикл вызова конструктора из оператора << (). Что тут происходит? :) </p>
спасибо!