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,
/* 인자들... */
)
;
|
(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, /* 인자들... */ ) ; |
(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,
/* args... */
)
;
|
(20) | |
|
void
*
T
::
operator
new
(
std::
size_t
count,
std:: align_val_t al, /* 인자들... */ ) ; |
(21) | (C++17부터) |
|
void
*
T
::
operator
new
[
]
(
std::
size_t
count,
std:: align_val_t al, /* 인수들... */ ) ; |
(22) | (C++17부터) |
요청된 바이트 수를 할당하려고 시도하며, 할당 요청은 실패할 수 있습니다(요청된 바이트 수가 0인 경우에도). 이러한 할당 함수들은 new expressions 에 의해 호출되어 새로운 객체가 초기화될 메모리를 할당합니다. 또한 일반 함수 호출 구문을 사용하여 호출될 수도 있습니다.
오버로드 ( 1-4 ) 는 <new> 헤더가 포함되지 않더라도 각 번역 단위에서 암시적으로 선언됩니다.
오버로드 선택 기준은 new expression 를 참조하십시오.
목차 |
매개변수
| count | - | 할당할 바이트 수 |
| ptr | - | 객체를 초기화할 메모리 영역에 대한 포인터 |
| tag | - | non-throwing 오버로드를 선택하는 데 사용되는 구분 태그 |
| al | - | 사용할 정렬 값, 유효하지 않은 값은 미정의 동작을 유발함 |
반환값
예외
전역 대체
오버로드 ( 1-8 ) 는 대체 가능 합니다. 기본 버전의 효과는 다음과 같습니다:
- 시도가 성공하면, 할당된 저장 공간에 대한 포인터를 반환합니다.
- 그렇지 않고 현재 설치된 new-handler 가 없는 경우, std::bad_alloc 을 throw합니다.
-
그렇지 않으면, 현재 설치된 new-handler를 호출합니다.
- new-handler가 반환되면, 다른 할당 시도를 시작합니다.
- 그렇지 않으면, 현재 호출을 종료합니다.
- 호출이 정상적으로 반환되면, 해당 호출의 결과를 반환합니다.
- 그렇지 않으면 null 포인터를 반환합니다.
|
독립형 구현 에서는 위에서 요구하는 동작을 기본 버전 ( 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[]
의 오버로드("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__를 초과하는 정렬을 가지는 객체 및 객체 배열을 할당할 때, 오버로드 해결은 두 번 수행됩니다: 먼저 정렬 인식 함수 시그니처에 대해, 그 다음 정렬 비인식 함수 시그니처에 대해 수행됩니다. 이는 확장된 정렬을 가진 클래스가 정렬 비인식 클래스별 할당 함수를 가지고 있는 경우, 전역 정렬 인식 할당 함수가 아닌 해당 함수가 호출된다는 것을 의미합니다. 이것은 의도된 동작입니다: 클래스 멤버가 해당 클래스를 처리하는 가장 적합한 방법을 알고 있을 것으로 기대됩니다. |
(C++17부터) |
|
정렬 요구사항이 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 를 초과하지 않는 객체 및 객체 배열을 할당할 때, 오버로드 해결은 두 번 수행됩니다: 먼저 정렬 인식이 없는 함수 시그니처에 대해, 그 다음 정렬 인식이 있는 함수 시그니처에 대해 수행됩니다. |
(C++20부터) |
#include <cstddef> #include <iostream> // 클래스별 할당 함수 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
)
). 일치하는 시그니처를 가진 placement
new
표현식이 호출할 해당 할당 함수를 찾을 때, 전역 범위를 검사하기 전에 클래스 범위에서 시작하며, 클래스 특정 placement
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 ) 는 대체될 수 없지만, 위에서 설명한 대로 동일한 시그니처를 가진 함수를 클래스 범위에서 정의할 수 있습니다. 또한, 배치 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)
|
정렬된 메모리를 할당합니다
(함수) |