Spec-Zone.ru › C++

operator delete, operator delete[]

Определено в заголовке <new>
функции обычного освобождения памяти
(1)
void operator delete  ( void* ptr ) throw();
(до C++11)
void operator delete  ( void* ptr ) noexcept;
(с C++11)
(2)
void operator delete[]( void* ptr ) throw();
(до 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)
функции размещенного освобождения памяти
(9)
void operator delete  ( void* ptr, const std::nothrow_t& tag ) throw();
(до C++11)
void operator delete  ( void* ptr, const std::nothrow_t& tag ) noexcept;
(с C++11)
(10)
void operator delete[]( void* ptr, const std::nothrow_t& tag ) throw();
(до 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)
функции неаллоцирующего размещенного освобождения памяти
(13)
void operator delete  ( void* ptr, void* place ) throw();
(до C++11)
void operator delete  ( void* ptr, void* place ) noexcept;
(с C++11)
(14)
void operator delete[]( void* ptr, void* place ) throw();
(до 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. Эти функции освобождения вызываются выражениями delete и выражениями new для освобождения памяти после уничтожения (или неудачной попытки создания) объектов с динамическим временем жизни. Их также можно вызвать с помощью обычного синтаксиса вызова функции.

1) Вызывается выражениями delete для освобождения памяти, ранее выделенной для одного объекта.
Поведение реализации стандартной библиотеки этой функции не определено, если ptr является нулевым указателем или является указателем, полученным ранее от реализации стандартной библиотеки operator new(std::size_t) или operator new(std::size_t, std::nothrow_t).
2) Вызывается выражениями delete[] для освобождения памяти, ранее выделенной для массива объектов.
Поведение реализации стандартной библиотеки этой функции не определено, если ptr является нулевым указателем или является указателем, полученным ранее от реализации стандартной библиотеки operator new[](std::size_t) или operator new[](std::size_t, std::nothrow_t).
3,4) То же самое, что и (1,2), но вызывается, если требование выравнивания превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__.
5,6) Вызывается вместо (1,2), если предоставлена пользовательская замена, за исключением того, что не определено, вызывается (1,2) или (5,6) при удалении объектов неполного типа и массивов типов неклассового и тривиально-разрушаемого класса. Менеджер памяти может использовать заданный размер для повышения эффективности.
Реализации стандартной библиотеки идентичны (1,2).
7,8) То же самое, что и (5,6), но вызывается, если требование выравнивания превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__.
9) Вызывается небросковыми выражениями new для одного объекта, если конструктор объекта выбрасывает исключение.
Реализация стандартной библиотеки ведет себя так же, как (1).
10) Вызывается небросковыми выражениями new[] для массива, если конструктор любого объекта выбрасывает исключение (после выполнения деструкторов всех объектов массива, которые были успешно созданы).
Реализация стандартной библиотеки ведет себя так же, как (2).
11,12) То же самое, что и (9,10), но вызывается, если требование выравнивания превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__.
13) Вызывается стандартным выражением размещенного new для одного объекта, если конструктор объекта выбрасывает исключение.
Реализация стандартной библиотеки этой функции ничего не делает.
14) Вызывается стандартной массивовой формой выражения размещенного new[], если конструктор любого объекта выбрасывает исключение (после выполнения деструкторов всех объектов, которые были успешно созданы).
Реализация стандартной библиотеки этой функции ничего не делает.
15) При определении вызывается пользовательским выражением размещенного new для одного объекта с соответствующей сигнатурой, если конструктор объекта выбрасывает исключение.
Если определена специфическая для класса версия (25), она вызывается вместо (9).
Если ни (25), ни (15) не предоставлены пользователем, функция освобождения не вызывается.
16) При определении вызывается пользовательской массивовой формой выражения размещенного new[] с соответствующей сигнатурой, если конструктор любого объекта выбрасывает исключение (после выполнения деструкторов для всех объектов, которые были успешно созданы).
Если определена специфическая для класса версия (26), она вызывается вместо (10).
Если ни (26), ни (16) не предоставлены пользователем, функция освобождения не вызывается.
17) Если определено, вызывается стандартными операциями delete при освобождении объекта типа T.
18) Если определено, вызывается стандартными операциями delete[] при освобождении массива объектов типа T.
19,20) Если определено, вызывается в приоритете перед (17,18), если требования к выравниванию превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__.
21) Если определено, и (17) не определено, вызывается стандартными операциями delete при освобождении объекта типа T.
22) Если определено, и (18) не определено, вызывается стандартными операциями delete[] при освобождении массива объектов типа T.
23,24) Если определено, и (19,20) не определены, вызывается в приоритете перед функциями без учёта выравнивания, если требования к выравниванию превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__.
25) Если определено, вызывается пользовательской операцией placement new с соответствующей сигнатурой, если конструктор объекта выбрасывает исключение.
Если эта функция не предоставлена, и соответствующая функция (15) также не предоставлена, ни одна функция освобождения не вызывается.
26) Если определено, вызывается пользовательской операцией placement new[] с соответствующей сигнатурой, если конструктор любого объекта выбрасывает исключение (после выполнения деструкторов для всех объектов, успешно созданных).
Если эта функция не предоставлена, и соответствующая функция (16) также не предоставлена, ни одна функция освобождения не вызывается.
27-30) Если определено, delete-выражение не выполняет деструктор для *p перед вызовом operator delete. Вместо этого, непосредственный вызов деструктора, например, с помощью p->~T();, становится обязанностью пользовательской операторной функции delete.

См. выражение delete для точных деталей правил разрешения перегрузки между функциями освобождения с учётом и без учёта выравнивания.

(с C++17)

Во всех случаях, если ptr является указателем null, стандартные функции освобождения не выполняют никаких действий. Если указатель, переданный стандартной функции освобождения, не был получен из соответствующей стандартной функции выделения, поведение не определено.

После возвращения стандартной функции освобождения все указатели, ссылающиеся на любую часть освобожденной памяти, становятся недействительными.

Обращение к указателю, ставшего недействительным таким образом, и передача его функции освобождения (двойное освобождение) приводит к неопределённому поведению. Любое другое использование является реализационно-определённым.

Параметры

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

Возвращаемое значение

(нет)

Исключения

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

(с C++11)

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

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

Заменяемые функции освобождения (1-12) неявно объявлены в каждом блоке трансляции, даже если заголовок <new> не включен. Эти функции заменяемые: предоставленная пользователем функция без имени с той же сигнатурой, определённая где-либо в программе, в любом файле исходного кода, заменяет соответствующую неявную версию для всей программы. Её объявление не должно быть видно.

Программа некорректна, без диагностики, если предоставлено более одной замены в программе или если замена объявлена с inline спецификатором. Программа некорректна, если замена определена в другом пространстве имён, кроме глобального, или если она определена как статическая функция без имени на глобальном уровне.

Реализации стандартной библиотеки для версий (9,10) без исключений напрямую вызывают соответствующие версии с исключениями (1,2). Реализации стандартной библиотеки для функций освобождения с учётом размера (5-8) напрямую вызывают соответствующие функции освобождения без учёта размера (1-4). Реализации стандартной библиотеки для функций освобождения без учёта размера для массивов с исключениями (2,4) напрямую вызывают соответствующие однообъектные формы (1,3). Таким образом, замена функций освобождения с исключениями для одного объекта (1,3) достаточна для обработки всех операций освобождения.

Глобальная замена 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[] с дополнительными пользовательскими параметрами ("размещаемые формы", (15,16)) могут быть объявлены на глобальном уровне как обычно и вызываются соответствующими размещаемыми формами выражений new, если конструктор объекта, который выделяется, выбрасывает исключение.

Размещаемые формы operator delete (13,14) в стандартной библиотеке не могут быть заменены и могут быть настраиваемы только если выражение placement new не использовало синтаксис ::new, предоставив специфическую для класса функцию placement 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 ищет соответствующую функцию освобождения, начиная с области видимости класса (массивная форма ищет в области видимости класса элемента массива) и переходит к глобальному пространству имён, если члены не найдены, как обычно. Обратите внимание, что в соответствии с правилами поиска имен, любые функции освобождения, объявленные в области видимости класса, скрывают все глобальные функции освобождения.

Если статический тип объекта, который удаляется, отличается от его динамического типа (например, при удалении полиморфного объекта через указатель на базовый класс) и если деструктор в статическом типе является виртуальным, однообъектная форма delete начинает поиск имени функции освобождения, начиная с места определения последнего переопределяющего члена его виртуального деструктора. Независимо от того, какая функция освобождения будет выполнена во время выполнения, статически видимая версия оператора 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[] с дополнительными параметрами, заданными пользователем («формы размещения», (25,26)), также могут быть определены как члены класса. Когда не удаётся выполнить выражение размещённого выделения памяти, поиск соответствующей функции размещённого удаления начинается в области видимости класса перед исследованием глобальной области видимости, и функция ищется с подписью, соответствующей размещённому выделению памяти:

#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

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

Примечания

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

Если поведение функции освобождения не удовлетворяет стандартным ограничениям, поведение является неопределённым.

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

  • Библиотечные версии operator new и operator delete
  • Версии пользовательской замены глобальных operator new и operator delete
  • std::calloc, std::malloc, std::realloc, std::aligned_alloc(с C++17), std::free

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

(с C++11)
Макросы проверки наличия функций Значение Std Функция
__cpp_sized_deallocation 201309L (C++14) Выделение размером
__cpp_impl_destroying_delete 201806L (C++20) Оператор удаления с уничтожением (поддержка компилятора)
__cpp_lib_destroying_delete 201806L (C++20) Оператор удаления с уничтожением (поддержка библиотеки)

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам 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&) были указаны, но никогда не могли быть вызваны
устранены избыточные перегрузки

См. также

operator newoperator new[]
функции выделения памяти
(функция)
return_temporary_buffer
(устарело в C++17)(удалено в C++20)
освобождает неинициализированную память
(шаблон функции)
free
освобождает ранее выделенную память
(функция)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/memory/new/operator_delete

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API