Namespaces
Variants

operator new, operator new[]

Начиная с 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 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, /* args... */ );
(11)
void* operator new[]( std::size_t count, /* args... */ );
(12)
void* operator new  ( std::size_t count,
                      std::align_val_t al, /* args... */ );
(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, /* args... */ );
(19)
void* T::operator new[]( std::size_t count, /* args... */ );
(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, /* args... */ );
(22) (начиная с C++17)

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

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

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

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

Параметры

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 — не определено.
  • Если попытка успешна, возвращает указатель на выделенную память, память выровнена по фундаментальному выравниванию(до C++17)память выровнена по __STDCPP_DEFAULT_NEW_ALIGNMENT__(начиная с C++17).
  • В противном случае, если в данный момент не установлен new-handler, генерирует std::bad_alloc.
  • В противном случае вызывает установленный new-handler.
    • Если new-handler возвращает управление, начинает новую попытку выделения.
    • В противном случае завершает текущий вызов.
2) Возвращает operator new(count).
3) Аналогично (1), за исключением того, что возвращаемая память выровнена по al.
4) Возвращает operator new(count, al).
5–8) Вызывает (1–4) соответственно с теми же аргументами, за исключением tag.
  • Если вызов возвращает управление в обычном порядке, возвращает результат этого вызова.
  • В противном случае возвращает нулевой указатель.

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

(начиная с 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[] с дополнительными пользовательскими параметрами («размещающие формы», версии (11–14)) могут объявляться в глобальной области видимости как обычно и вызываются соответствующими размещающими формами выражений 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__, разрешение перегрузки выполняется дважды: сначала для сигнатур функций, учитывающих выравнивание, затем для сигнатур функций, не учитывающих выравнивание. Это означает, что если класс с расширенным выравниванием (new-extended alignment) имеет специфичную для класса функцию выделения, не учитывающую выравнивание, то будет вызвана именно она, а не глобальная функция выделения, учитывающая выравнивание. Это сделано намеренно: предполагается, что член класса лучше знает, как обрабатывать этот класс.

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

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

(начиная с 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[] с дополнительными пользовательскими параметрами («размещающие формы») также могут быть определены как члены класса (19-22)). Когда выражение new с соответствующей сигнатурой ищет вызываемую функцию выделения памяти, оно сначала просматривает область видимости класса, а затем глобальную область видимости; если предоставлена размещающая функция new, специфичная для класса, то вызывается она.

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

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

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

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