- (C++11~) get_new_handler()가 추가되었습니다.
- (C++11~) pointer_traits가 추가되어 포인터와 유사한 타입들을 다루는 표준화된 방법을 제공합니다.
- (C++11~) aligned_alloc()이 추가되어 정렬된 메모리를 할당할 수 있습니다.
- (C++11~) addressof()가 추가되어
operator &()
가 연산자 오버로딩 되었어도 실제 주소를 구할 수 있습니다.
- (C++11~) align()이 추가되어 메모리 정렬했을 때의 포인터를 구할 수 있습니다.
- (C++11~) allocator_traits, allocator_arg, uses_allocator, scoped_allocator_adaptor가 추가되었습니다.
- (C++11~) uninitialized_copy_n이 추가되었습니다.
- (C++11~) 가비지 컬렉터 지원이 추가되었습니다.
- (C++17~) integer_sequence가 추가되어 컴파일 타임에 정수 타입의 시퀀스를 만들 수 있습니다.
- (C++17~) align_val_t가 추가되었습니다.
- (C++17~) launder()가 추가되어 위치 지정 생성으로 생성된 개체의 합법적인 포인터를 얻을 수 있습니다.
- (C++17~) polymorphic_allocator가 추가되어 할당시 런타임 다형성을 지원합니다. 메모리 리소스를 사용하여 메모리 풀을 손쉽게 만들 수 있습니다.
- (C++17~) uninitialized_move(), uninitialized_default_construct(), uninitialized_value_construct(), destroy(), destroy_at()가 추가되어 위치 지정 생성자 호출과 소멸자 호출의 새로운 방법을 제공합니다.
- (C++20~) to_address(), assume_aligned()가 추가되었습니다.
- (C++20~) destroying_delete가 추가되었습니다.
- (C++20~) uses_allocator_construction_args, make_obj_using_allocator, uninitialized_construct_using_allocator가 추가되었습니다.
- (C++20~) construct_at()이 추가되었습니다.
C스타일 메모리 관리
항목 |
내용 |
malloc() |
메모리를 할당합니다. |
calloc() |
(작성중) |
realloc() |
(작성중) |
free() |
메모리를 해제합니다. |
aligned_alloc() (C++17~) |
정렬된 메모리를 할당합니다. |
저수준 메모리 관리
launder()는 위치 지정 생성으로 생성한 개체의 포인터를 다룰때 합법적인 방법을 제공합니다.
다음예에서 ptr
과 newPtr
은 위치 지정 생성을 이용하여 동일한 메모리 공간에 만들어 집니다. 그래서, ptr
로 접근하던, newPtr
로 접근하던 동일한 데이터여야 합니다. 하지만 이전 이름인 ptr
로 다루는 것이 찜찜하기도 한데요,
그냥 찜찜할 뿐만 아니라 const인 경우는 컴파일러 최적화에 의해 이전 값인 1
이 될 수도 있습니다. 그래서 보통 사용하지 않는데요,
launder()를 사용하면, newPtr
로 위치 지정 생성을 했더라도 이전 이름인 ptr
로 접근할 수 있습니다. 따라서 std::launder(ptr)->m_X == 3
와 같이 이전 개체 이름인 ptr
로 newPtr
이 생성한 값에 합법적으로 접근할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| class A {
public:
const int m_X; // const 멤버 입니다.
int m_Y;
A(int x, int y) : m_X{x}, m_Y{y} {}
};
A* ptr = new A{1, 2};
EXPECT_TRUE(ptr->m_X == 1 && ptr->m_Y == 2);
// 위치 지정 생성으로 ptr 위치에 다시 생성합니다.
A* newPtr = new(ptr) A{3, 4};
EXPECT_TRUE(newPtr->m_X == 3 && newPtr->m_Y == 4);
// 이전 포인터인 ptr로 다루려면, launder를 사용합니다.
EXPECT_TRUE((ptr->m_X == 1 || ptr->m_X == 3)); // (△) 비권장. 컴파일러 최적화에 의해 const 변수는 이전값 1을 가질 수도 있습니다.
EXPECT_TRUE(ptr->m_Y == 4); // (△) 비권장. 불법입니다만, 잘 동작합니다.
EXPECT_TRUE(std::launder(ptr)->m_X == 3); // launder를 이용하여 합법적으로 사용할 수 있습니다.
delete std::launder(ptr);
|
(C++11~) pointer_traits
포인터와 유사한 타입들을 다루는 표준화된 방법을 제공합니다.
항목 |
내용 |
pointer (C++11~) |
포인터 타입입니다. |
element_type (C++11~) |
포인터가 가리키는 값의 타입입니다. |
difference_type (C++11~) |
포인터끼리 뺀 값의 타입입니다. |
template<typename U> using rebind (C++11~) |
U 에 바인딩되는 타입입니다. |
pointer pointer_to(element_type& r); (C++11~) |
element_type 을 pointer 타입으로 변환합니다. |
(C++11~) addressof()
operator &()
가 연산자 오버로딩 되었어도 실제 주소를 리턴합니다.
1
2
| template<typename T>
T* addressof(T& arg) noexcept;
|
(C++11~) align()
space
크기의 버퍼 공간에 size
크기의 개체를 alignment
로 메모리 정렬했을때의 연속된 메모리 포인터인 ptr
을 구합니다.
1
2
3
4
5
6
| void* align(
std::size_t alignment, // 메모리 정렬, alignof() 값
std::size_t size, // 졍렬할 요소의 크기
void*& ptr, // 최소 space 바이트의 연속된 메모리 포인터
std::size_t& space // 작업할 버퍼의 최대 크기
);
|
할당자
기존에는 allocator
만 있었으나(할당자(Allocator) 참고), 좀더 많은 내용이 보강되었습니다.
항목 |
내용 |
allocator |
컨테이너 등 STL에서 개체 할당에 사용합니다. |
allocator_traits (C++11~) |
(작성중) |
allocator_arg (C++11~) |
(작성중) |
uses_allocator (C++11~) |
(작성중) |
scoped_allocator_adaptor (C++11~) |
(작성중) |
polymorphic_allocator (C++17~) |
런타임 다형성을 지원하는 할당자입니다. 메모리 리소스를 사용하여 메모리 풀을 손쉽게 만들 수 있습니다. |
uses_allocator_construction_args (C++20~) |
(작성중) |
make_obj_using_allocator (C++20~) |
(작성중) |
uninitialized_construct_using_allocator (C++20~) |
(작성중) |
allocator_result (C++23~) |
(작성중) |
메모리 유틸리티 작업
C++17 부터는 uninitialized_move(), uninitialized_default_construct(), uninitialized_value_construct(), destroy(), destroy_at()가 추가되어 위치 지정 생성자 호출과 소멸자 호출의 새로운 방법을 제공합니다.
항목 |
내용 |
uninitialized_copy()
uninitialized_copy_n() (C++11~) |
메모리를 복사합니다. |
uninitialized_fill()
uninitialized_fill_n() |
메모리를 특정 값으로 채웁니다. |
uninitialized_move() (C++17~)
uninitialized_move_n() (C++17~) |
메모리의 값을 이동시킵니다. |
uninitialized_default_construct() (C++17~)
uninitialized_default_construct_n() (C++17~) |
주어진 메모리 영역 개체들을 기본 생성자(new T )로 초기화 합니다. 자동 제로 초기화를 하지 않습니다. |
uninitialized_value_construct() (C++17~)
uninitialized_value_construct_n() (C++17~) |
주어진 메모리 영역 개체들을 값 생성자(new T() )로 초기화 합니다. 자동 제로 초기화를 합니다. |
destroy() (C++17~)
destroy_n() (C++17~) |
주어진 메모리 영역 개체들의 소멸자를 호출합니다. |
destroy_at() (C++17~) |
주어진 메모리 영역 개체의 소멸자를 호출합니다. |
construct_at() (C++20~) |
주어진 메모리 영역 개체의 생성자를 호출합니다. |
다음과 같은 T
개체가 있다고 할때,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| class T {
private:
int m_X;
int m_Y;
public:
T() :
m_X{10},
m_Y{20} {
std::cout << "T : Constructor" << std::endl;
}
~T() {
std::cout << "T : Destructor" << std::endl;
}
int GetX() const {return m_X;}
int GetY() const {return m_Y;}
};
|
다음은 스택에 버퍼를 생성하고, 3개의 T
개체를 생성하고 소멸시키는 예입니다.
위치 지정 생성 방식을 사용하면 다음과 같고,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| unsigned char buffer[sizeof(T) * 3]; // T 개체 3개를 저장할 수 있는 스택 영역을 확보합니다.
// 3개의 생성자 호출
T* t1 = new(static_cast<void*>(buffer + sizeof(T) * 0)) T;
T* t2 = new(static_cast<void*>(buffer + sizeof(T) * 1)) T;
T* t3 = new(static_cast<void*>(buffer + sizeof(T) * 2)) T;
EXPECT_TRUE(t1->GetX() == 10 && t1->GetY() == 20);
EXPECT_TRUE(t2->GetX() == 10 && t2->GetY() == 20);
EXPECT_TRUE(t3->GetX() == 10 && t3->GetY() == 20);
// 3개의 소멸자 호출
t1->~T();
t2->~T();
t3->~T();
|
uninitialized_default_construct() 와 destroy()를 사용한 방식은 다음과 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
| unsigned char data[sizeof(T) * 3]; // T 개체 3개를 저장할 수 있는 스택 영역을 확보합니다.
auto begin{reinterpret_cast<T*>(data)};
auto end{begin + 3};
// 요소 3개의 생성자 호출
std::uninitialized_default_construct(begin, end);
EXPECT_TRUE((begin + 0)->GetX() == 10 && (begin + 0)->GetY() == 20);
EXPECT_TRUE((begin + 1)->GetX() == 10 && (begin + 1)->GetY() == 20);
EXPECT_TRUE((begin + 2)->GetX() == 10 && (begin + 2)->GetY() == 20);
// 요소 3개의 소멸자 호출
std::destroy(begin, end);
|
실행 결과를 보면 두 경우 모두 생성자 3회, 소멸자 3회 호출된 것을 알 수 있습니다.
1
2
3
4
5
6
| T : Constructor
T : Constructor
T : Constructor
T : Destructor
T : Destructor
T : Destructor
|
(C++11~)가비지 컬렉터 지원
항목 |
내용 |
declare_reachable() (C++11~C++23) |
(작성중) |
undeclare_reachable() (C++11~C++23) |
(작성중) |
declare_no_pointers() (C++11~C++23) |
(작성중) |
undeclare_no_pointers() (C++11~C++23) |
(작성중) |
pointer_safety (C++11~C++23) |
(작성중) |
get_pointer_safety() (C++11~C++23) |
(작성중) |
초기화 되지 않은 스토리지
항목 |
내용 |
raw_storage_iterator (~C++17) |
(작성중) |
get_temporary_buffer (~C++17) |
(작성중) |
return_temporary_buffer (~C++17) |
(작성중) |
(C++20~) 메모리 관리
항목 |
내용 |
to_address() (C++20~) |
일반 포인터나 스마트 포인터 구분없이 실제 관리되는 메모리 주소를 접근하는 일관된 방법을 제공합니다. |
assume_aligned(ptr) (C++20~) |
ptr 을 메모리 정렬된 포인터로 변환합니다. |
to_address()는 실제 메모리에서 관리되는 포인터를 구하는 일관된 방법을 제공합니다.
1
2
3
4
5
6
| int* rawPtr{new int{0}};
std::shared_ptr<int> sp{rawPtr};
EXPECT_TRUE(rawPtr == std::to_address(rawPtr)); // 일반 포인터나 스마트 포인터 구분없이 실제 관리되는 메모리 주소를 접근하는 일관된 방법을 제공합니다.
EXPECT_TRUE(rawPtr == std::to_address(sp));
EXPECT_TRUE(rawPtr == sp.get());
|
(C++23~) 스마트 포인트 어뎁터
항목 |
내용 |
out_ptr_t (C++23~)
out_ptr() (C++23~) |
(작성중) |
inout_ptr_t (C++23~)
inout_ptr() (C++23~) |
(작성중) |
(C++23~) 명시적 수명 관리
항목 |
내용 |
start_lifetime_as (C++23~)
start_lifetime_as_array (C++23~) |
(작성중) |
댓글남기기