[new와 placement new]
메모리를 할당하면서 객체를 생성하는 new 연산과 달리, placement new는 이미 확보된 메모리 공간에 객체를 생성할 때 사용하는 특수한 new 연산자입니다.
> new
MyClass* obj = new MyClass();
new는 위와 같이 실시하며, 동적 메모리에서 공간을 할당한 뒤, 그 공간에서 생성자를 호출합니다.
> placement new
char buffer[sizeof(MyClass)];
MyClass obj = new(buffer) MyClass();
placement new는 미리 확보된 메모리 공간(위에서는 buffer)가 존재하고, 그 공간을 생성자 호출용으로만 활용합니다. 이 과정에서 새 메모리 할당은 발생하지 않습니다.
[placement new 문법]
연산자 정의는 다음과 같이 이루어져 있습니다.
void* operator new(size_t size, void* ptr) noexcept;
////////////////////////////////////////////////////
T* obj = new(ptr) T(constructor_args...);
확보된 ptr 주소를 인자로 받아, 그 위치에 객체를 생성하는 것입니다. 아래는 실제 사용 예시에 대한 코드입니다.
#include <iostream>
#include <new> // placement new를 사용하려면 필요
class MyClass
{
public:
int Value;
MyClass(int _Value) : Value(_Value)
{
std::cout << "Constructor: " << Value << std::endl;
}
~MyClass()
{
std::cout << "Destructor: " << Value << std::endl;
}
};
int main()
{
// 메모리만 확보
alignas(MyClass) char buffer[sizeof(MyClass)];
// 확보된 메모리에 객체 생성
MyClass* obj = new(buffer) MyClass(123);
std::cout << "Value = " << obj->Value << std::endl;
// 명시적으로 소멸자 호출 (delete X)
obj->~MyClass();
return 0;
}
///////////////////////////////////////////
<출력>
Constructor: 123
Value = 123
Destructor: 123
[사용 이유]
placement new의 활용 목적 대부분은 메모리풀에서 활용하기 위함에 있습니다. 미리 큰 버퍼를 만들어두고, placement new를 통해 필요한 위치에 객체를 생성하는 것입니다.
void* pool = malloc(sizeof(MyClass) * 100);
MyClass* obj = new(pool) MyClass();
/////////////////////////////////////////////////
<메모리풀 예시>
class MemoryPool
{
char* Pool;
size_t Offset;
public:
MemoryPool(size_t Size)
{
Pool = new char[Size];
Offset = 0;
}
~MemoryPool() { delete[] Pool; }
template<typename T, typename... Args>
T* Allocate(Args&&... args)
{
void* Ptr = Pool + Offset;
Offset += sizeof(T);
return new(Ptr) T(std::forward<Args>(args)...);
}
};
추가로, 객체의 생성과 소멸 시점을 직접 관리하고 싶은 경우에도 활용합니다. shared_ptr 등에는 내부 구현에 placement new를 활용하고 있습니다.
[주의 사항]
placement new는 실제로 new와 같이 메모리를 할당하는 것이 아니라, 미리 할당해둔 메모리 영역을 활용하는 것이기 때문에 delete 연산자를 호출하기보단 명시적으로 소멸자를 호출하는 것이 좋습니다. 또한 이미 생성된 영역에 대해 다시 생성을 실시하면 같은 영역에 객체가 덮어씌워질 수 있습니다.
'C++' 카테고리의 다른 글
[C++] 빌드 과정 (0) | 2025.09.03 |
---|---|
[C++] 완벽한 전달(Perfact Forwarding)과 std::forward (0) | 2025.05.16 |
[C++] 이동 생성자와 std::move() (0) | 2025.05.16 |
[C++] 좌측값과 우측값(lvalue and rvalue) (0) | 2025.05.15 |
[C++] 복사 생략(Copy Elision) (0) | 2025.05.15 |