Namespaces
Variants

operator delete, operator delete[]

С ru.cppreference.net
 
 
Библиотека утилит
Поддержка языка
Поддержка типов (базовые типы, RTTI)
Макросы проверки возможностей библиотеки (C++20)
Программные утилиты
Вариативные функции
Поддержка корутин (C++20)
Поддержка контрактов (C++26)
Трёхстороннее сравнение
(C++20)
(C++20)(C++20)(C++20)    
(C++20)(C++20)(C++20)

Общие утилиты
Операторы отношений (устарело в C++20)
 
Библиотека управления памятью
Аллокаторы
Ресурсы памяти
Неинициализированное хранилище (до C++20*)
Поддержка сборщика мусора (до C++23)
 
 
Определён в заголовке <new>
Заменяемые обычные функции освобождения
void operator delete  ( void* ptr ) throw();
(1) (до C++11)
void operator delete  ( void* ptr ) noexcept;
(начиная с C++11)
void operator delete[]( void* ptr ) throw();
(2) (до C++11)
void operator delete[]( void* ptr ) noexcept;
(начиная с C++11)
void operator delete  ( void* ptr, std::align_val_t al ) noexcept;
(3) (начиная с C++17)
void operator delete[]( void* ptr, std::align_val_t al ) noexcept;
(4) (начиная с C++17)
void operator delete  ( void* ptr, std::size_t sz ) noexcept;
(5) (начиная с C++14)
void operator delete[]( void* ptr, std::size_t sz ) noexcept;
(6) (начиная с C++14)
void operator delete  ( void* ptr, std::size_t sz,
                        std::align_val_t al ) noexcept;
(7) (начиная с C++17)
void operator delete[]( void* ptr, std::size_t sz,
                        std::align_val_t al ) noexcept;
(8) (начиная с C++17)
Заменяемые размещающие функции освобождения
void operator delete  ( void* ptr, const std::nothrow_t& tag ) throw();
(9) (до C++11)
void operator delete  ( void* ptr, const std::nothrow_t& tag ) noexcept;
(начиная с C++11)
void operator delete[]( void* ptr, const std::nothrow_t& tag ) throw();
(10) (до C++11)
void operator delete[]( void* ptr, const std::nothrow_t& tag ) noexcept;
(начиная с C++11)
void operator delete  ( void* ptr, std::align_val_t al,
                        const std::nothrow_t& tag ) noexcept;
(11) (начиная с C++17)
void operator delete[]( void* ptr, std::align_val_t al,
                        const std::nothrow_t& tag ) noexcept;
(12) (начиная с C++17)
Невыделяющие размещающие функции освобождения
void operator delete  ( void* ptr, void* place ) throw();
(13) (до C++11)
void operator delete  ( void* ptr, void* place ) noexcept;
(начиная с C++11)
void operator delete[]( void* ptr, void* place ) throw();
(14) (до C++11)
void operator delete[]( void* ptr, void* place ) noexcept;
(начиная с C++11)
Пользовательские размещающие функции освобождения
void operator delete  ( void* ptr, args... );
(15)
void operator delete[]( void* ptr, args... );
(16)
Обычные функции освобождения, специфичные для класса
void T::operator delete  ( void* ptr );
(17)
void T::operator delete[]( void* ptr );
(18)
void T::operator delete  ( void* ptr, std::align_val_t al );
(19) (начиная с C++17)
void T::operator delete[]( void* ptr, std::align_val_t al );
(20) (начиная с C++17)
void T::operator delete  ( void* ptr, std::size_t sz );
(21)
void T::operator delete[]( void* ptr, std::size_t sz );
(22)
void T::operator delete  ( void* ptr, std::size_t sz, std::align_val_t al );
(23) (начиная с C++17)
void T::operator delete[]( void* ptr, std::size_t sz, std::align_val_t al );
(24) (начиная с C++17)
Размещающие функции освобождения, специфичные для класса
void T::operator delete  ( void* ptr, args... );
(25)
void T::operator delete[]( void* ptr, args... );
(26)
Обычные уничтожающие функции освобождения, специфичные для класса
void T::operator delete( T* ptr, std::destroying_delete_t );
(27) (начиная с C++20)
void T::operator delete( T* ptr, std::destroying_delete_t,
                         std::align_val_t al );
(28) (начиная с C++20)
void T::operator delete( T* ptr, std::destroying_delete_t, std::size_t sz );
(29) (начиная с C++20)
void T::operator delete( T* ptr, std::destroying_delete_t,
                         std::size_t sz, std::align_val_t al );
(30) (начиная с C++20)

Освобождает хранилище, ранее выделенное соответствующим operator new или operator new[]. Эти функции освобождения вызываются выражениями delete и delete[] выражениями и размещающими new выражениями для освобождения памяти после уничтожения (или неудачного конструирования) объектов с динамическим сроком хранения. Они также могут быть вызваны с помощью обычного синтаксиса вызова функций.

1-12) Заменяемые функции освобождения. Стандартная библиотека предоставляет реализации по умолчанию для этих функций, о действии реализаций по умолчанию см. ниже.
1-8) Вызываются выражениями delete и delete[] выражениями. Инвалидирует любой ненулевой ptr.
9-12) Вызываются размещающими new выражениями при сбое инициализации. operator delete[] инвалидирует любой ненулевой ptr.
Если ptr не является нулевым указателем и выполняется одно из следующих условий, поведение не определено:
  • Для operator delete, значение ptr не представляет адрес блока памяти, выделенного более ранним вызовом (возможно, заменённого) operator new(std::size_t) (для перегрузок (1,5,9)) или operator new(std::size_t, std::align_val_t) (для перегрузок (3,7,11)) который не был инвалидирован промежуточным вызовом operator delete.
  • Для operator delete[], значение ptr не представляет адрес блока памяти, выделенного более ранним вызовом (возможно, заменённого) operator new[](std::size_t) (для перегрузок (2,6,10)) или operator new[](std::size_t, std::align_val_t) (для перегрузок (4,8,12)) который не был инвалидирован промежуточным вызовом operator delete[].
13,14) Вызываются размещающими new выражениями, которые вызвали невыделяющую размещающую функцию выделения, когда любая часть инициализации в выражении завершается выбросом исключения. Не выполняет никаких действий.
15-30) Пользовательские функции освобождения, вызываемые delete, delete[] и размещающими new выражениями.
27-30) Если определены, delete выражения не выполняют деструктор для *ptr перед вызовом operator delete. Вместо этого прямой вызов деструктора, например через ptr->~T();, становится ответственностью этого operator delete.

Перегрузки (1-8) неявно объявляются в каждой единице трансляции, даже если заголовок <new> не включён.

См. delete выражение для критериев выбора перегрузки.

Параметры

ptr - указатель на блок памяти для освобождения или нулевой указатель
sz - размер, переданный соответствующей функции выделения памяти
place - указатель, используемый в качестве параметра размещения в соответствующем placement new
tag - тег разрешения перегрузки, соответствующий тегу, используемому в non-throwing operator new
al - выравнивание объекта или элемента массива, который был выделен
args - произвольные параметры, соответствующие функции размещающего выделения памяти (могут включать std::size_t и std::align_val_t )

Исключения

Все функции освобождения памяти являются noexcept ( true ) если не указано иное в объявлении.

(начиная с C++11)

Если функция освобождения завершается выбрасыванием исключения, поведение не определено , даже если она объявлена с noexcept ( false ) (начиная с C++11) .

Глобальные замены

Перегрузки ( 1-12 ) являются заменяемыми . Эффекты версий по умолчанию следующие:

1) Если ptr является нулевым, ничего не делает. В противном случае освобождает память, выделенную предыдущим вызовом operator new .
2) Вызывает operator delete ( ptr ) как если бы перегрузка (1) могла вернуть память, выделенную предыдущим вызовом operator new [ ] .
3) То же, что и (1) .
4) Вызывает operator delete ( ptr, al ) как если бы перегрузка (3) могла освободить память, выделенную предыдущим вызовом operator new [ ] .
5) Вызывает operator delete ( ptr ) .
6) Вызывает operator delete [ ] ( ptr ) .
7) Вызывает operator delete ( ptr, al ) .
8) Вызывает operator delete [ ] ( ptr, al ) .
9) Вызывает operator delete ( ptr ) .
10) Вызывает operator delete [ ] ( ptr ) .
11) Вызывает operator delete ( ptr, al ) .
12) Вызывает operator delete [ ] ( ptr, al ) .

Глобальная замена operator new / delete :

#include <cstdio>
#include <cstdlib>
#include <new>
// no inline, required by [replacement.functions]/3
void* operator new(std::size_t sz)
{
    std::printf("1) new(size_t), size = %zu\n", sz);
    if (sz == 0)
        ++sz; // avoid std::malloc(0) which may return nullptr on success
    if (void *ptr = std::malloc(sz))
        return ptr;
    throw std::bad_alloc{}; // required by [new.delete.single]/3
}
// no inline, required by [replacement.functions]/3
void* operator new[](std::size_t sz)
{
    std::printf("2) new[](size_t), size = %zu\n", sz);
    if (sz == 0)
        ++sz; // avoid std::malloc(0) which may return nullptr on success
    if (void *ptr = std::malloc(sz))
        return ptr;
    throw std::bad_alloc{}; // required by [new.delete.single]/3
}
void operator delete(void* ptr) noexcept
{
    std::puts("3) delete(void*)");
    std::free(ptr);
}
void operator delete(void* ptr, std::size_t size) noexcept
{
    std::printf("4) delete(void*, size_t), size = %zu\n", size);
    std::free(ptr);
}
void operator delete[](void* ptr) noexcept
{
    std::puts("5) delete[](void* ptr)");
    std::free(ptr);
}
void operator delete[](void* ptr, std::size_t size) noexcept
{
    std::printf("6) delete[](void*, size_t), size = %zu\n", size);
    std::free(ptr);
}
int main()
{
    int* p1 = new int;
    delete p1;
    int* p2 = new int[10]; // guaranteed to call the replacement in C++11
    delete[] p2;
}

Возможный вывод:

// Compiled with GCC-5 in C++17 mode to obtain the following:
1) op new(size_t), size = 4
4) op delete(void*, size_t), size = 4
2) op new[](size_t), size = 40
5) op delete[](void* ptr)

Перегрузки operator delete и operator delete [ ] с дополнительными пользовательскими параметрами ("placement forms", ( 15,16 ) ) могут быть объявлены в глобальной области видимости как обычно и вызываются соответствующими placement формами выражений new , если конструктор выделяемого объекта выбрасывает исключение.

Стандартные библиотечные формы размещающего operator delete и operator delete [ ] ( 13,14 ) не могут быть заменены и могут быть кастомизированы только если выражение размещающего new не использовало синтаксис :: new , путем предоставления класс-специфичного размещающего delete ( 25,26 ) с соответствующей сигнатурой: void T :: operator delete ( void * , void * ) или void T :: operator delete [ ] ( void * , void * ) .

Перегрузки, специфичные для класса

Функции освобождения памяти ( 17-24 ) могут быть определены как статические функции-члены класса. Эти функции освобождения, если они предоставлены, вызываются выражениями delete при удалении объектов ( 17,19,21 ) и массивов ( 18,20,22 ) данного класса, за исключением случаев, когда выражение delete использовало форму :: delete которая обходит поиск в области видимости класса. Ключевое слово static является необязательным для объявлений этих функций: независимо от использования ключевого слова, функция освобождения всегда является статической функцией-членом.

Выражение delete ищет подходящую функцию освобождения памяти, начиная с области видимости класса (для массива поиск происходит в области видимости класса элемента массива) и переходит в глобальную область видимости, если не найдено подходящих членов, как обычно. Обратите внимание, что согласно правилам поиска имен , любые функции освобождения памяти, объявленные в области видимости класса, скрывают все глобальные функции освобождения памяти.

Если статический тип объекта, который удаляется, отличается от его динамического типа (например, при удалении полиморфного объекта через указатель на базовый класс), и если деструктор в статическом типе является виртуальным, форма удаления для одиночного объекта начинает поиск имени функции освобождения памяти с точки определения финального переопределителя его виртуального деструктора. Независимо от того, какая функция освобождения будет выполнена во время выполнения, статически видимая версия operator delete должна быть доступна для успешной компиляции. В других случаях, при удалении массива через указатель на базовый класс или при удалении через указатель на базовый класс с невиртуальным деструктором, поведение не определено.

Если перегрузка с одним аргументом ( 17,18 ) не предоставлена, но предоставлена перегрузка с поддержкой размера, принимающая std::size_t в качестве второго параметра ( 21,22 ) , то для обычного освобождения памяти вызывается форма с поддержкой размера, и среда выполнения C++ передает размер освобождаемого объекта в качестве второго аргумента. Если определены обе формы, вызывается версия без поддержки размера.

#include <cstddef>
#include <iostream>
// sized class-specific deallocation functions
struct X
{
    static void operator delete(void* ptr, std::size_t sz)
    {
        std::cout << "custom delete for size " << sz << '\n';
        ::operator delete(ptr);
    }
    static void operator delete[](void* ptr, std::size_t sz)
    {
        std::cout << "custom delete for size " << sz << '\n';
        ::operator delete[](ptr);
    }
};
int main()
{
    X* p1 = new X;
    delete p1;
    X* p2 = new X[10];
    delete[] p2;
}

Возможный вывод:

custom delete for size 1
custom delete for size 18

Перегрузки operator delete и operator delete [ ] с дополнительными пользовательскими параметрами ("placement forms", ( 25,26 ) ) также могут быть определены как члены класса. Когда выражение placement new с ошибкой ищет соответствующую placement delete функцию для вызова, оно начинает поиск в области видимости класса перед изучением глобальной области видимости и ищет функцию с сигнатурой, соответствующей placement new :

#include <cstddef>
#include <iostream>
#include <stdexcept>
struct X
{
    X() { throw std::runtime_error("X(): std::runtime_error"); }
    // custom placement new
    static void* operator new(std::size_t sz, bool b)
    {
        std::cout << "custom placement new called, b = " << b << '\n';
        return ::operator new(sz);
    }
    // custom placement delete
    static void operator delete(void* ptr, bool b)
    {
        std::cout << "custom placement delete called, b = " << b << '\n';
        ::operator delete(ptr);
    }
};
int main()
{
    try
    {
        [[maybe_unused]] X* p1 = new (true) X;
    }
    catch (const std::exception& ex)
    {
        std::cout << ex.what() << '\n';
    }
}

Вывод:

custom placement new called, b = 1
custom placement delete called, b = 1
X(): std::runtime_error

Если оператор delete на уровне класса operator delete является шаблонной функцией, он должен иметь возвращаемый тип void , первый аргумент void * , и должен иметь два или более параметров. Другими словами, только формы размещения могут быть шаблонами. Экземпляр шаблона никогда не является обычной функцией освобождения, независимо от его сигнатуры. Специализация шаблонного оператора delete выбирается с помощью вывода аргументов шаблона .

Примечания

Вызов специфичного для класса T :: operator delete в полиморфном классе — это единственный случай, когда статическая функция-член вызывается через динамическую диспетчеризацию.

Следующие функции должны быть потокобезопасными:

Вызовы этих функций, которые выделяют или освобождают определенную единицу памяти, происходят в едином общем порядке, и каждый такой вызов освобождения happens-before следующего выделения (если таковое имеется) в этом порядке.

(since C++11)
Макрос тестирования возможностей Значение Стандарт Возможность
__cpp_sized_deallocation 201309L (C++14) Sized deallocation
__cpp_impl_destroying_delete 201806L (C++20) Destroying operator delete (поддержка компилятора)
__cpp_lib_destroying_delete 201806L (C++20) Destroying operator delete (поддержка библиотеки)

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение в опубликованной версии Корректное поведение
CWG 220 C++98 пользовательские функции освобождения памяти могли генерировать исключения генерация исключения из функции освобождения памяти
приводит к неопределённому поведению
CWG 1438 C++98 любое использование невалидного значения указателя было неопределённым поведением только разыменование и освобождение памяти являются таковыми
LWG 206 C++98 замена ( 2 ) не влияла на поведение по умолчанию для ( 10 ) поведение по умолчанию
изменяется соответствующим образом
LWG 298 C++98 замена ( 1 ) не влияла на поведение по умолчанию для ( 9 ) поведение по умолчанию
изменяется соответствующим образом
LWG 404 C++98 замены заменяемых функций освобождения
памяти могли быть объявлены inline
запрещено, диагностика не требуется
LWG 2458 C++14 перегрузки принимающие ( void * , std:: size_t , const
std:: nothrow_t & ) были специфицированы, но никогда не могли быть вызваны
удалены ложные перегрузки

Смотрите также

[static] (C++23)
освобождает память, ранее полученную от operator new
(публичная статическая функция-член std::generator<Ref,V,Allocator>::promise_type )
функции выделения памяти
(функция)
(устарело в C++17) (удалено в C++20)
освобождает неинициализированную память
(шаблон функции)
освобождает ранее выделенную память
(функция)