Namespaces
Variants

operator new , operator new[]

From cppreference.net
< cpp ‎ | memory ‎ | new
Utilities library
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
Изменения: - `/* args... */` → `/* аргументы... */` (перевод комментария) - Все HTML-теги, атрибуты и C++ код сохранены без изменений - Форматирование полностью сохранено (Примечание: В данном фрагменте HTML отсутствует текстовое содержимое для перевода - присутствуют только HTML-теги и атрибуты, которые согласно инструкциям не подлежат переводу)
Определено в заголовке <new>
Заменяемые функции выделения памяти
void * operator new ( std:: size_t count ) ;
(1)
void * operator new [ ] ( std:: size_t count ) ;
(2)
void * operator new ( std:: size_t count, std:: align_val_t al ) ;
(3) (начиная с C++17)
void * operator new [ ] ( std:: size_t count, std:: align_val_t al ) ;
(4) (начиная с C++17)
Заменяемые функции выделения памяти без генерации исключений
void * operator new ( std:: size_t count, const std:: nothrow_t & tag ) ;
(5) (noexcept начиная с C++11)
void * operator new [ ] ( std:: size_t count, const std:: nothrow_t & tag ) ;
(6) (noexcept начиная с C++11)
void * operator new ( std:: size_t count, std:: align_val_t al,
const std:: nothrow_t & tag ) noexcept ;
(7) (начиная с C++17)
void * operator new [ ] ( std:: size_t count, std:: align_val_t al,
const std:: nothrow_t & tag ) noexcept ;
(8) (начиная с C++17)
Неразмещающие функции размещения с размещением
void * operator new ( std:: size_t count, void * ptr ) ;
(9) (noexcept начиная с C++11)
(constexpr начиная с C++26)
void * operator new [ ] ( std:: size_t count, void * ptr ) ;
(10) (noexcept начиная с C++11)
(constexpr начиная с C++26)
Пользовательские функции размещающего выделения памяти
void * operator new ( std:: size_t count, /* аргументы... */ ) ;
(11)
void * operator new [ ] ( std:: size_t count, /* аргументы... */ ) ;
(12)
void * operator new ( std:: size_t count,
std:: align_val_t al, /* аргументы... */ ) ;
(13) (начиная с C++17)
void * operator new [ ] ( std:: size_t count,
std:: align_val_t al, /* args... */ ) ;
(14) (начиная с C++17)
Функции выделения памяти, специфичные для класса
void * T :: operator new ( std:: size_t count ) ;
(15)
void * T :: operator new [ ] ( std:: size_t count ) ;
(16)
void * T :: operator new ( std:: size_t count, std:: align_val_t al ) ;
(17) (начиная с C++17)
void * T :: operator new [ ] ( std:: size_t count, std:: align_val_t al ) ;
(18) (начиная с C++17)
Функции размещающего выделения памяти для конкретного класса
void * T :: operator new ( std:: size_t count, /* аргументы... */ ) ;
(19)
void * T :: operator new [ ] ( std:: size_t count, /* аргументы... */ ) ;
(20)
void * T :: operator new ( std:: size_t count,
std:: align_val_t al, /* args... */ ) ;
(21) (начиная с C++17)
void * T :: operator new [ ] ( std:: size_t count,
std:: align_val_t al, /* аргументы... */ ) ;
(22) (начиная с C++17)

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

1-8) Replaceable функции распределения памяти. Стандартная библиотека предоставляет реализации по умолчанию для этих функций; для описания эффектов реализаций по умолчанию см. ниже .
9,10) Вызывается стандартными выражениями размещающего new . Не выполняет никаких действий и возвращает ptr без изменений.
Если эта функция вызывается через размещающий new и ptr является нулевым указателем, поведение не определено.
11-22) Пользовательские функции выделения памяти, вызываемые выражениями new .

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

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

Содержание

Параметры

count - количество байт для выделения
ptr - указатель на область памяти для инициализации объекта
tag - тег устранения неоднозначности для выбора непорождающих исключения перегрузок
al - выравнивание для использования, недопустимое значение приводит к неопределенному поведению

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

1-4) Если выделение памяти завершается успешно, возвращается ненулевой указатель p0 , который указывает на соответствующим образом выровненную память размером не менее size и отличается от любого ранее возвращенного значения p1 , за исключением случая, когда это значение p1 было впоследствии передано заменяемой функции освобождения памяти ; если выделение памяти завершается неудачей, функция не возвращает управление (генерируется исключение, см. ниже).
5-8) То же, что и ( 1-4 ) , но возвращает нулевой указатель при неудачном выделении памяти.
9,10) ptr
11-22) То же, что и ( 1-4 ) если функция не возвращает управление при неудачном выделении памяти, в противном случае то же, что и ( 5-8 ) .

Исключения

1-4) Выбрасывает исключение типа, соответствующего обработчику типа std::bad_alloc при неудачном выделении памяти.
11-22) То же, что и ( 1-4 ) если функция не возвращает управление при неудачном выделении памяти, в противном случае то же, что и ( 5-8 ) .

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

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

1) Пытается выделить запрошенную память. Не определено, включает ли попытка вызов std::malloc или std::aligned_alloc .
  • Если попытка успешна, возвращает указатель на выделенную память.
  • В противном случае, если в данный момент не установлен new-handler , генерирует исключение std::bad_alloc .
  • В противном случае вызывает текущий установленный new-handler.
    • Если new-handler возвращает управление, начинает новую попытку выделения.
    • В противном случае завершает текущий вызов.
2) Возвращает operator new ( count ) .
3) То же, что и (1) .
4) Возвращает operator new ( count, al ) .
5-8) Вызывает (1-4) соответственно с теми же аргументами, за исключением tag .
  • Если вызов завершается нормально, возвращает результат этого вызова.
  • В противном случае возвращает нулевой указатель.

В автономных реализациях , определяется реализацией, удовлетворяют ли стандартные версии ( 1-8 ) требованиям к поведению, указанным выше. Рекомендуется, чтобы в автономных реализациях, если какие-либо из этих стандартных версий соответствуют требованиям hosted-реализации, все они должны соответствовать.

(since C++26)

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

Нераспределяющие формы размещающего operator new ( 9,10 ) из стандартной библиотеки не могут быть заменены и могут быть настроены только если размещающее выражение new не использовало синтаксис :: new , путем предоставления специализированного размещающего new ( 19,20 ) для класса с соответствующей сигнатурой: void * T :: operator new ( std:: size_t , void * ) или void * T :: operator new [ ] ( std:: size_t , void * ) .

Форма размещения void * operator new ( std:: size_t , std:: size_t ) не разрешена, поскольку соответствующая сигнатура функции освобождения, void operator delete ( void * , std:: size_t ) , является обычной (не размещающей) функцией освобождения.

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

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

Функции выделения памяти как для одиночных объектов, так и для массивов могут быть определены как публичные статические функции-члены класса (версии ( 15-18 ) ). Если они определены, эти функции выделения вызываются выражениями new для выделения памяти под одиночные объекты и массивы данного класса, за исключением случаев, когда выражение new использовало форму :: new , которая обходит поиск в области видимости класса. Ключевое слово static для этих функций является опциональным: независимо от его использования, функция выделения памяти остается статической функцией-членом.

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

При выделении памяти для объектов и массивов объектов, выравнивание которых превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__ , разрешение перегрузки выполняется дважды: сначала для сигнатур функций с учетом выравнивания, затем для сигнатур функций без учета выравнивания. Это означает, что если класс с расширенным выравниванием имеет специфичную для класса функцию выделения без учета выравнивания, то будет вызвана именно эта функция, а не глобальная функция выделения с учетом выравнивания. Это сделано намеренно: предполагается, что член класса лучше знает, как обрабатывать этот класс.

(since C++17)

При выделении памяти для объектов и массивов объектов, выравнивание которых не превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__ , разрешение перегрузки выполняется дважды: сначала для сигнатур функций без учета выравнивания, затем для сигнатур функций с учетом выравнивания.

(since C++20)
#include <cstddef>
#include <iostream>
// class-specific allocation functions
struct X
{
    static void* operator new(std::size_t count)
    {
        std::cout << "custom new for size " << count << '\n';
        return ::operator new(count);
    }
    static void* operator new[](std::size_t count)
    {
        std::cout << "custom new[] for size " << count << '\n';
        return ::operator new[](count);
    }
};
int main()
{
    X* p1 = new X;
    delete p1;
    X* p2 = new X[10];
    delete[] p2;
}

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

custom new for size 1
custom new[] for size 10

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

При выделении памяти для объектов и массивов объектов, выравнивание которых превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__ , разрешение перегрузки для форм размещения выполняется дважды, так же как и для обычных форм: сначала для сигнатур функций с учетом выравнивания, затем для сигнатур функций без учета выравнивания.

(since C++17)

При выделении памяти для объектов и массивов объектов, выравнивание которых не превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__ , разрешение перегрузки для форм размещения выполняется дважды, так же как и для обычных форм: сначала для сигнатур функций без учета выравнивания, затем для сигнатур функций с учетом выравнивания.

(since C++20)
#include <cstddef>
#include <iostream>
#include <stdexcept>
struct X
{
    X() { throw std::runtime_error(""); }
    // custom placement new
    static void* operator new(std::size_t count, bool b)
    {
        std::cout << "custom placement new called, b = " << b << '\n';
        return ::operator new(count);
    }
    // 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&)
    {}
}

Вывод:

custom placement new called, b = 1
custom placement delete called, b = 1

Если оператор operator new на уровне класса является шаблонной функцией, он должен иметь возвращаемый тип void * , первый аргумент std::size_t , и должен иметь два или более параметров. Другими словами, только формы размещения могут быть шаблонами.

Примечания

Хотя неразмещающий placement new ( 9,10 ) не может быть заменён, функция с такой же сигнатурой может быть определена в области видимости класса, как описано выше. Кроме того, разрешены глобальные перегрузки, которые выглядят как placement new , но принимают тип не-void указателя в качестве второго аргумента. Поэтому код, который хочет гарантировать вызов настоящего placement new (например, std::allocator::construct ), должен использовать :: new и также приводить указатель к void * .

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

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

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

(since C++11)

Не определено, вызывают ли библиотечные версии operator new какие-либо вызовы std::malloc или std::aligned_alloc (начиная с C++17) .

Для загрузки больших файлов отображение файлов в память с помощью специфичных для операционной системы функций, например, mmap в POSIX или CreateFileMapping ( A / W ) вместе с MapViewOfFile в Windows, предпочтительнее выделения буфера для чтения файла.

Макрос тестирования возможностей Значение Стандарт Возможность
__cpp_lib_freestanding_operator_new 202306L (C++26) поддержка автономного режима для заменяемого operator new [1]
0 (C++26) отсутствие поддержки автономного режима
__cpp_lib_constexpr_new 202406L (C++26) constexpr размещающий new и new [ ]
  1. Формально, этот макрос раскрывается в 202306L если все стандартные версии заменяемых глобальных функций выделения памяти соответствуют требованиям hosted-реализации.

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

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

DR Applied to Behavior as published Correct behavior
CWG 521 C++98 any class derived from std::bad_alloc could be thrown,
even if the std::bad_alloc base is ambiguous or inaccessible
the exception thrown should match
a handler of type std::bad_alloc
LWG 9 C++98 multiple calls for allocating zero
bytes could yield the same pointer
only allowed if all such previously
yielded pointers have been
passed to deallocation functions
LWG 206 C++98 replacing the replaceable allocation functions did
not affect the default behaviors of the corresponding
replaceable non-throwing allocation functions
the default behaviors
change accordingly
LWG 404 C++98 replacements of the replaceable allocation
functions could be declared inline
prohibited, no diagnostic required

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2024):
  • 17.7 Управление динамической памятью [support.dynamic]
  • Стандарт C++20 (ISO/IEC 14882:2020):
  • 17.6 Управление динамической памятью [support.dynamic]
  • Стандарт C++17 (ISO/IEC 14882:2017):
  • 21.6 Управление динамической памятью [support.dynamic]
  • Стандарт C++14 (ISO/IEC 14882:2014):
  • 18.6 Управление динамической памятью [support.dynamic]
  • Стандарт C++11 (ISO/IEC 14882:2011):
  • 18.6 Управление динамической памятью [support.dynamic]
  • Стандарт C++03 (ISO/IEC 14882:2003):
  • 18.4 Управление динамической памятью [lib.support.dynamic]
  • Стандарт C++98 (ISO/IEC 14882:1998):
  • 18.4 Управление динамической памятью [lib.support.dynamic]

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

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