Рассмотрим программу ниже. Это было упрощено из сложного случая. Он не может удалить предыдущую выделенную память, если я не удалю виртуальный деструктор в классе Obj. Я не понимаю, почему два адреса из вывода программы отличаются, только если присутствует виртуальный деструктор.
// GCC 4.4
#include <iostream>
using namespace std;
class Arena {
public:
void* alloc(size_t s) {
char* p = new char[s];
cout << "Allocated memory address starts at: " << (void*)p << '\n';
return p;
}
void free(void* p) {
cout << "The memory to be deallocated starts at: " << p << '\n';
delete [] static_cast<char*> (p); // the program fails here
}
};
struct Obj {
void* operator new[](size_t s, Arena& a) {
return a.alloc(s);
}
virtual ~Obj() {} // if I remove this everything works as expected
void destroy(size_t n, Arena* a) {
for (size_t i = 0; i < n; i++)
this[n - i - 1].~Obj();
if (a)
a->free(this);
}
};
int main(int argc, char** argv) {
Arena a;
Obj* p = new(a) Obj[5]();
p->destroy(5, &a);
return 0;
}
Это результат работы программы в моей реализации, когда присутствует виртуальный деструктор:
Адрес выделенной памяти начинается с: 0x8895008 Память, которая должна быть освобождена, начинается с: 0x889500c
RUN FAILED ( значение выхода 1)
Пожалуйста, не спрашивайте, что программа должна делать. Как я уже сказал, это связано с более сложным случаем, когда Arena представляет собой интерфейс для различных типов памяти. В этом примере память просто выделяется и освобождается из кучи.