Свободная память
// полагаем, что p указывает на s байтов памяти, выделенной Employee::operator new()
Данное предположение не вполне корректно: p также может являться нулевым указателем, и в этом случае определяемый пользователем operator delete() должен корретно себя вести, т.е. ничего не делать.
Запомните: определяя operator delete(), вы обязаны правильно обрабатывать удаление нулевого указателя! Т.о. код должен выглядеть следующим образом: void Employee::operator delete(void* p, size_t s) { if (!p) return; // игнорируем нулевой указатель
// полагаем, что p указывает на s байтов памяти, выделенной // Employee::operator new() и освобождаем эту память // для дальнейшего использования }
Интересно отметить, что стандартом специально оговорено, что аргумент p функции template <class T> void std::allocator::deallocate(pointer p, size_type n);
не может быть нулевым. Без этого замечания использование функции Pool::free в разделе 19.4.2. "Распределители памяти, определяемые пользователем" было бы некорректным.
В принципе, освобождение памяти осуществляется тогда внутри деструктора (который знает размер).
Именно так. Т.е. если вы объявили деструктор некоторого класса A::~A() { // тело деструктора }
то компилятором (чаще всего) будет сгенерирован следующий код // псевдокод A::~A(A *const this, bool flag) { if (this) { // тело деструктора if (flag) delete(this, sizeof(A)); } }
Ввиду чего функция void f(Employee* ptr) { delete ptr; }
превратится в // псевдокод void f(Employee* ptr) { Employee::~Employee(ptr, true); }
и т.к. класс Employee имеет виртуальный деструктор, это в конечном итоге приведет к вызову соответствующего метода.