본문 바로가기
코드

위치 지정 new

by ehei 2021. 2. 17.

이 방법은 이렇다. 힙에서 할당하는 대신 인자로 건네진 포인터를 기점으로 할당하고 생성자를 호출한다. 영어로는 placement new라고 불린다.

 

#include <iostream>
#include <new>

struct Test
{
	int v0{};

	Test() { std::cout << "Test()" << std::endl; }
	~Test() { std::cout << "~Test()" << std::endl; }
};

int main()
{
	constexpr auto size = sizeof(Test) * 10;
	alignas(Test) unsigned char buf[size]{};
	
	Test* v = new(buf) Test;
	v->~Test();
    ...

 

위의 코드에서 그 예를 살필 수 있다. buf를 스택 영역에서 할당받았다. new를 통해 이 공간에 객체를 셋업한다. 

 

이런 기능이 필요한 이유는 다음과 같다. 힙을 할당하는 건 많은 비용이 든다. 메모리의 정합성을 유지하기 위해 운영체제가 수행해야하는 작업이 있다. 가상 메모리, 페이지 단위 관리, 그리고 메모리 파편화를 피하기 위한 재배치가 그런 것들의 예이다. 여기에 드는 비용은 프로그래머가 예상할 수 없다. 그러나 발생하면 치명적이다. 정체불명의 랙이 생길 수도 있다. 따라서 보통은 메모리풀이란 개념으로 대량의 연속된 메모리를 할당받는다. 그리고 위치지정 new를 이용하여 객체를 그곳에 생성한다. 여기서 책의 내용을 인용해보자.

 

... 하지만 명시적인 소멸자 호출을 이용하지 않고 표준 라이브러리 vector 수준의 효율적인 범용 컨테이너를 구현하기는 어려울 것이다. ...

C++ 프로그래밍 언어 4판, 비야네 스트롭스트룹

이 기능을 썼다면 소멸자를 직접 호출해야하는 점을 유의하자. 유감스럽게도 위치지정 delete 같은 건 없다. 객체가 생성된 공간은 운영체제가 관리해주는 곳이 아니다. 따라서 객체의 소멸 처리를 위해 직접 소멸자를 호출해야 한다. 그렇다면 vector는 어떻게 처리하고 있는가?

 

// <xmemory>
...

template <class _Alloc>
struct _Default_allocator_traits { // traits for std::allocator
    ...
    // placement new 
    template <class _Objty, class... _Types>
    static void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) {
    	::new (const_cast<void*>(static_cast<const volatile void*>(_Ptr))) _Objty(_STD forward<_Types>(_Args)...);
    }

    ...
    // calling destructor explicitly
    template <class _Uty>
    static void destroy(_Alloc&, _Uty* const _Ptr) {
    	_Ptr->~_Uty();
    }
    ...
}

 

책의 저자가 밝혔듯이 _Ptr이란 공간을 사용한다. 위치지정 new를 이용해 그곳에 클래스를 생성한다. 소멸자 호출도 직접 수행하여 객체의 정리 작업을 호출하고 있다.

 

new expression - cppreference.com

'코드' 카테고리의 다른 글

Game Server Performance on Tom Clancy's The Division 2  (0) 2021.04.20
std::tuple<Ts...> ➔ std::tuple<U<Ts>...>  (0) 2021.03.25
메모리  (0) 2021.02.15
alignas  (0) 2021.02.03
make_index_sequence 구현  (0) 2021.01.27