Любая функция распределения для класса T является статическим членом (даже если не объявлен явно static).
[ Example:
class Arena; struct B { void* operator new(std::size_t, Arena*); }; struct D1 : B { }; Arena* ap; void foo(int i) { new (ap) D1; // calls B::operator new(std::size_t, Arena*) new D1[i]; // calls ::operator new[](std::size_t) new D1; // ill-formed: ::operator new(std::size_t) hidden }
— end example ]
Когда объект удаляется с помощью delete-expressiona, функция освобождения ( для объектов, не являющихся массивами или для массивов) вызывается (неявно) для освобождения памяти, занятой объектом ( ).operator delete() operator delete[]() [basic.stc.dynamic.deallocation]
Поиск специфичной для класса функции освобождения памяти является частью общей функции поиска ([expr.delete]) и происходит следующим образом. Если delete-expression используется для освобождения объекта класса, статический тип которого имеет виртуальный деструктор, функция освобождения - это функция, выбранная в точке определения виртуального деструктора динамического типа ([class.dtor]).118 В противном случае, если delete-expression используется для освобождения объекта класса T или его массива, статический и динамический типы объекта должны быть идентичными, а имя функции освобождения ищется в области видимости T. Если этот поиск не может найти имя,[expr.delete]продолжается поиск общей функции освобождения памяти ( ). Если результат поиска неоднозначен или недоступен, или если поиск выбирает функцию освобождения размещения, программа имеет неправильный формат.
Любая функция освобождения класса X является статическим членом (даже если не объявлена явно static). [ Example:
class X { void operator delete(void*); void operator delete[](void*, std::size_t); }; class Y { void operator delete(void*, std::size_t); void operator delete[](void*); };
— end example ]
Поскольку функции распределения и освобождения членов static не могут быть виртуальными. [ Однако, когда of a относится к объекту типа класса, потому что фактически вызванная функция освобождения ищется в области действия класса, который является динамическим типом объекта, если деструктор является виртуальным, эффект тот же . Например, Note: cast-expressiondelete-expression
struct B {
virtual ~B();
void operator delete(void*, std::size_t);
};
struct D : B {
void operator delete(void*);
};
void f() {
B* bp = new D;
delete bp; // 1: uses D::operator delete(void*)
}
Здесь память для объекта класса, неD являющегося массивом, освобождается D::operator delete()из-за виртуального деструктора. ] [ Виртуальные деструкторы не влияют на фактически вызываемую функцию освобождения, когда a ссылается на массив объектов типа класса. Например, — end note Note: cast-expressiondelete-expression
struct B { virtual ~B(); void operator delete[](void*, std::size_t); }; struct D : B { void operator delete[](void*, std::size_t); }; void f(int i) { D* dp = new D[i]; delete [] dp; // uses D::operator delete[](void*, std::size_t) B* bp = new D[i]; delete[] bp; // undefined behavior }
— end note ]
Доступ к функции освобождения проверяется статически. Следовательно, даже если на самом деле может быть выполнен другой, статически видимая функция освобождения должна быть доступна. [ Example: Для вызова в строке «// 1» выше, если бы B::operator delete() это было так private, выражение удаления было бы неправильно сформировано. ] — end example
[ Note: Если функция освобождения не имеет явного значения noexcept-specifier, она не выбрасывает exception specification. ] — end note
Подобное положение не требуется для версии массива, operator delete поскольку [expr.delete] в этой ситуации требуется, чтобы статический тип удаляемого объекта был таким же, как и его динамический тип.