Advanced C++

[C++] 메모리 관리 (3) 주소 기반 초기화 placement new

로파이 2021. 10. 6. 19:41

new 연산자

new 연산자는 C++에서 특정 개체 타입을 동적할당하고 초기화하는데 사용한다.

 

placement new

표현식 : new (Address) Type (Initialize arguments);

이미 메모리 할당이 이루어진 주소 공간에 해당 타입으로 초기화할 때 사용한다. 주로 메모리 풀이나 가비지 컬렉터와 같은 응용에 사용된다. new 연산자를 이용하지만 실제로 동적 할당이 이루어지는 것이 아니며 실제 행동은 초기화만 진행된다.

segmentation fault가 발생한 경우 : 전달한 Address 주소가 유효하지 않은 메모리 주소 혹은 null 포인터일 경우 발생할 수 있다. 

메모리 해제 : 힙 메모리의 경우 실제로 동적 할당을 수행한 주소를 가진 포인터를 삭제 시키는 것으로 해제하며 스택 메모리의 경우 따로 해제할 필요가 없다.

#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <crtdbg.h>
#include <iostream>

using namespace std;

struct Complex
{
	float Real;
	float Img;

	Complex()
		:
		Real(0.f), Img(0.f)
	{}

	Complex(float r, float i)
		:
		Real(r), Img(i)
	{}
};

void Print(Complex* c)
{
	printf("Complex 0x%p : (%.1f,%.1f)\n", c, c->Real, c->Img);
}

int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

	unsigned char buf[100];

	printf("Buffer 0x%p\n", buf);

	// using placement new
	Complex* p1 = new(buf) Complex(1.f, 1.f);
	Complex* p2 = new(buf + sizeof(Complex)) Complex(2.f, 2.f);
	Complex* p3 = new(buf + 2 *sizeof(Complex)) Complex(3.f, 3.f);

	
	Print(p1);
	Print(p2);
	Print(p3);

	return 0;
}

placement new를 이용한 개체 초기화

buf라는 100 바이트 크기를 가진 지역 변수에 배열 처럼 Complex 구조체 3개를 초기화하는 방법을 보인다. 메모리가 연속적이므로 캐시에 유리하고 꼭 같은 타입을 초기화할 필요없이 메모리만 할당되어 있다면 여러 타입의 개체를 placement new를 사용하여 원하는 주소에 할당할 수 있다. 

 

- 힙 메모리를 이용

힙 메모리를 이용해서도 개체를 할당할 수 있다. 

int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

	std::unique_ptr<char[]> buffer(new char[100]);

	char* pBuf = buffer.get();
	printf("Buffer 0x%p\n", pBuf);

	// using placement new
	Complex* p1 = new(pBuf) Complex(1.f, 1.f);
	Complex* p2 = new(pBuf + sizeof(Complex)) Complex(2.f, 2.f);
	Complex* p3 = new(pBuf + 2 *sizeof(Complex)) Complex(3.f, 3.f);

	Print(p1);
	Print(p2);
	Print(p3);

	return 0;
}