operator new, operator new[]
| 헤더에 정의됨 <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 표현식에 의해 호출되어 새 객체가 초기화될 메모리를 할당합니다. 일반 함수 호출 구문을 사용하여 호출할 수도 있습니다.
new을(를) 통해 호출되고 ptr이(가) 널 포인터인 경우, 동작은 정의되지 않습니다.new 표현식에 의해 호출되는 사용자 정의 할당 함수.오버로드 (1-4)은(는) <new> 헤더가 포함되지 않더라도 각 번역 단위에 암시적으로 선언됩니다.
오버로드 선택 기준은 new 표현식을(를) 참조하십시오.
매개변수
| count | - | 할당할 바이트 수 |
| ptr | - | 객체를 초기화할 메모리 영역에 대한 포인터 |
| tag | - | non-throwing 오버로드를 선택하는 데 사용되는 구분 태그 |
| al | - | 사용할 정렬 값, 유효하지 않은 값은 미정의 동작을 유발함 |
반환값
예외
전역 대체
오버로드 (1-8)는 대체 가능. 기본 버전의 효과는 다음과 같습니다:
- 시도가 성공하면 할당된 저장 공간에 대한 포인터를 반환하며, 저장 공간이 기본 정렬로 정렬됩니다(C++17까지)저장 공간이
__STDCPP_DEFAULT_NEW_ALIGNMENT__(C++17부터). - 그렇지 않으면, 현재 new 핸들러가 설치되어 있지 않으면 std::bad_alloc을 던집니다.
- 그렇지 않으면 현재 설치된 new 핸들러를 호출합니다.
- new 핸들러가 반환되면 다른 할당 시도를 시작합니다.
- 그렇지 않으면 현재 호출을 종료합니다.
operator new(count)을 반환합니다.al로 정렬됩니다.operator new(count, al)을 반환합니다.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*)를 제공하여 사용자 정의할 수 있습니다.
|
배치 폼 |
(C++14부터) |
클래스별 오버로드
단일 객체 및 배열 할당 함수는 모두 클래스의 public static 멤버 함수로 정의될 수 있습니다(버전 (15-18)). 정의된 경우, 이러한 할당 함수는 new 표현식에 의해 호출되어 이 클래스의 단일 객체 및 배열에 대한 메모리를 할당합니다. 단, new 표현식이 클래스 범위 조회를 우회하는 형식 ::new을 사용한 경우는 예외입니다. 키워드 static은 이러한 함수에 대해 선택적입니다. 사용 여부와 관계없이 할당 함수는 정적 멤버 함수입니다.
new 표현식은 먼저 클래스 범위에서 적절한 할당 함수의 이름을 찾고, 그 후에 전역 범위에서 찾습니다. 이름 조회 규칙에 따라, 클래스 범위에서 선언된 할당 함수는 이 클래스의 객체를 할당하려는 new 표현식에 대해 모든 전역 할당 함수를 숨깁니다.
|
정렬이 |
(C++17부터) |
|
정렬이 |
(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가 제공되면 해당 함수가 호출됩니다.
|
정렬이 |
(C++17부터) |
|
정렬이 |
(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 [ ] |
- ↑ 공식적으로, 이 매크로는 모든 기본 버전의 대체 가능한 전역 할당 함수들이 호스팅 구현의 요구 사항을 충족하는 경우 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 멤버 함수)
|
|
메모리 해제 함수들
(함수) |
|
|
(C++11)
|
현재 new 핸들러를 얻습니다
(함수) |
|
new 핸들러를 등록합니다
(함수) |
|
|
(C++17에서 사용 중단됨)
(C++20에서 제거됨)
|
초기화되지 않은 저장 공간을 얻습니다
(함수 템플릿) |
|
메모리를 할당합니다
(함수) |
|
|
(C++17)
|
정렬된 메모리를 할당합니다
(함수) |