Namespaces
Variants

operator new, operator new[]

cppreference.net에서
< cpp | memory | new
 
 
유틸리티 라이브러리
일반 유틸리티
관계 연산자 (C++20부터 비권장)
정수 비교 함수
(C++20)(C++20)(C++20)    
(C++20)
Swap 및 타입 연산
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
공통 어휘 타입
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)



 
메모리 관리 라이브러리
할당자
메모리 자원
초기화되지 않은 저장소 (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) (C++11부터 noexcept)
void* operator new[]( std::size_t count, const std::nothrow_t& tag );
(6) (C++11부터 noexcept)
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) (C++11부터 noexcept)
(C++26부터 constexpr)
void* operator new[]( std::size_t count, void* ptr );
(10) (C++11부터 noexcept)
(C++26부터 constexpr)
사용자 정의 배치 할당 함수
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부터)

요청된 바이트 수를 할당하려 시도하며, 할당 요청은 실패할 수 있습니다(요청된 바이트 수가 0인 경우에도). 이 할당 함수들은 new 표현식에 의해 호출되어 새 객체가 초기화될 메모리를 할당합니다. 일반 함수 호출 구문을 사용하여 호출할 수도 있습니다.

1-8) 대체 가능 할당 함수. 표준 라이브러리는 이러한 함수들에 대한 기본 구현을 제공합니다. 기본 구현의 효과는 아래를 참조하십시오.
9,10) 표준 배치 new 표현식에 의해 호출됩니다. 아무 동작도 수행하지 않고 ptr을(를) 변경하지 않고 반환합니다.
이 함수가 배치 new을(를) 통해 호출되고 ptr이(가) 널 포인터인 경우, 동작은 정의되지 않습니다.
11-22) new 표현식에 의해 호출되는 사용자 정의 할당 함수.

오버로드 (1-4)은(는) <new> 헤더가 포함되지 않더라도 각 번역 단위에 암시적으로 선언됩니다.

오버로드 선택 기준은 new 표현식을(를) 참조하십시오.

매개변수

count - 할당할 바이트 수
ptr - 객체를 초기화할 메모리 영역에 대한 포인터
tag - non-throwing 오버로드를 선택하는 데 사용되는 구분 태그
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 핸들러가 설치되어 있지 않으면 std::bad_alloc을 던집니다.
  • 그렇지 않으면 현재 설치된 new 핸들러를 호출합니다.
    • new 핸들러가 반환되면 다른 할당 시도를 시작합니다.
    • 그렇지 않으면 현재 호출을 종료합니다.
2) operator new(count)을 반환합니다.
3) (1)과 동일하지만, 반환된 저장 공간이 al로 정렬됩니다.
4) operator new(count, al)을 반환합니다.
5-8) (1-4)을 각각 동일한 인수로 호출합니다. 단, tag는 제외합니다.
  • 호출이 정상적으로 반환되면, 해당 호출의 결과를 반환합니다.
  • 그렇지 않으면 널 포인터를 반환합니다.

독립형 구현에서, 기본 버전이 (1-8) 위에서 요구된 동작을 충족하는지는 구현 정의입니다. 독립형 구현은 이러한 기본 버전 중 하나라도 호스팅 구현의 요구 사항을 충족하면 모두 충족해야 한다고 권장됩니다.

(C++26부터)

전역 operators 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부터)

클래스별 오버로드

단일 객체 및 배열 할당 함수는 모두 클래스의 public static 멤버 함수로 정의될 수 있습니다(버전 (15-18)). 정의된 경우, 이러한 할당 함수는 new 표현식에 의해 호출되어 이 클래스의 단일 객체 및 배열에 대한 메모리를 할당합니다. 단, new 표현식이 클래스 범위 조회를 우회하는 형식 ::new을 사용한 경우는 예외입니다. 키워드 static은 이러한 함수에 대해 선택적입니다. 사용 여부와 관계없이 할당 함수는 정적 멤버 함수입니다.

new 표현식은 먼저 클래스 범위에서 적절한 할당 함수의 이름을 찾고, 그 후에 전역 범위에서 찾습니다. 이름 조회 규칙에 따라, 클래스 범위에서 선언된 할당 함수는 이 클래스의 객체를 할당하려는 new 표현식에 대해 모든 전역 할당 함수를 숨깁니다.

정렬이 __STDCPP_DEFAULT_NEW_ALIGNMENT__을 초과하는 객체 및 객체 배열을 할당할 때, 오버로드 해결은 두 번 수행됩니다. 먼저 정렬 인식 함수 시그니처에 대해, 그 다음 정렬 비인식 함수 시그니처에 대해 수행됩니다. 즉, new 확장 정렬을 가진 클래스에 정렬 비인식 클래스별 할당 함수가 있는 경우, 전역 정렬 인식 할당 함수 대신 해당 함수가 호출됩니다. 이는 의도된 것입니다. 클래스 멤버가 해당 클래스를 가장 잘 처리하는 방법을 알고 있을 것으로 예상되기 때문입니다.

(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이어야 하며, 두 개 이상의 매개변수가 있어야 합니다. 즉, 배치 형식만 템플릿이 될 수 있습니다.

참고 사항

비할당 배치 new ( 9,10 ) 는 대체될 수 없지만, 위에서 설명한 대로 동일한 시그니처를 가진 함수를 클래스 범위에서 정의할 수 있습니다. 또한, 배치 new 와 유사하지만 두 번째 인자로 void가 아닌 포인터 타입을 취하는 전역 오버로드가 허용됩니다. 따라서 실제 배치 new 가 호출되도록 보장하려는 코드(예: std::allocator::construct )는 :: new 를 사용해야 하며 포인터를 void * 로 캐스팅해야 합니다.

할당 해제 함수의 동작이 기본 제약 조건을 충족하지 않으면, 그 동작은 정의되지 않습니다.

다음 함수들은 스레드 안전성이 요구됩니다:

특정 저장 단위를 할당하거나 해제하는 이러한 함수들의 호출은 단일 전체 순서로 발생하며, 각 해제 호출은 이 순서에서 다음 할당(있는 경우)에 대해 happens-before 관계를 가집니다.

(C++11부터)

라이브러리 버전의 operator new 가 std::malloc 또는 std::aligned_alloc (C++17부터) 를 호출하는지는 명시되지 않습니다.

대용량 파일을 로드할 때는 파일 읽기를 위한 버퍼를 할당하는 것보다 OS별 함수를 통한 파일 매핑, 예를 들어 mmap on POSIX 또는 CreateFileMapping ( A / W )와 함께 MapViewOfFile on 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 로 확장됩니다.

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 521 C++98 std::bad_alloc 에서 파생된 모든 클래스가 throw될 수 있었음,
std::bad_alloc 기본 클래스가 모호하거나 접근 불가능한 경우에도
throw된 예외는
std::bad_alloc 타입의 핸들러와 일치해야 함
LWG 9 C++98 제로 바이트 할당에 대한 다중 호출이
동일한 포인터를 반환할 수 있었음
이전에 반환된 모든 해당 포인터가
할당 해제 함수에 전달된 경우에만 허용됨
LWG 206 C++98 대체 가능 할당 함수를 교체해도
해당 대체 가능 비예외 할당 함수들의
기본 동작에 영향을 주지 않았음
기본 동작이
그에 따라 변경됨
LWG 404 C++98 대체 가능 할당 함수의 교체본이
inline 으로 선언될 수 있었음
금지됨, 진단 불필요

참고문헌

  • 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 의 public static 멤버 함수)
메모리 해제 함수들
(함수)
현재 new 핸들러를 얻습니다
(함수)
new 핸들러를 등록합니다
(함수)
(C++17에서 사용 중단됨) (C++20에서 제거됨)
초기화되지 않은 저장 공간을 얻습니다
(함수 템플릿)
메모리를 할당합니다
(함수)
정렬된 메모리를 할당합니다
(함수)