C++ 중급 - Placement New

타입·2024년 2월 18일
0

C++ 공부

목록 보기
8/17

new/delete

  • new 내부 동작
    Point* p1 = new Point(1, 2);
  1. 메모리 할당
    void* p = operator new(sizeof(Point))
  2. 생성자 호출
    Point* p1 = new(p) Point(1, 2);
  • delete 내부 동작
    delete p1;
  1. 소멸자 호출
    p1->~Point();
  2. 메모리 해지
    operator delete(p1);
  • operator new() / operator delete()
    메모리를 할당/해지하는 C++ 표준 함수
    < new > 헤더
    std namespace 아닌 global namespace

Placement New

이미 할당된 메모리에 대해 생성자를 명시적으로 호출하기 위한 new

// 새로운 메모리를 할당하고 객체 생성 (생성자 호출)
new Point(1,2);

// 이미 할당된 메모리(p)에 객체 생성 (생성자만 호출)
new(p) Point(1,2); // placement new
  • 생성자를 명시적으로 호출
  1. new(p) Point(1,2);
  2. std::construct_at(p, 1, 2);
    C++20, < memory > 헤더
  • 소멸자를 명시적으로 호출
  1. p->~Point();
  2. std::destroy_at(p);
    C++17, < memory > 헤더
  • 객체를 생성/파괴 하는 방법
  1. new/delete 사용
  2. 메모리 할당과 생성자 호출을 분리

    메모리 할당
    operator new(sizeof(Point));

    생성자 호출
    new(p) Point(1, 2); // placement new
    std::construct_at(p, 1, 2); // C++20

    소멸자 호출
    p->~Point();
    std::destroy_at(p); // C++17

    메모리 해지
    operator delete(p);


Placement New 사용 이유

  • 왜 메모리 할당과 생성자 호출을 분리하는가
// Point 객체 3개를 힙에 연속적으로 생성하고 싶음
new Point[3]; // 디폴트 생성자가 없는 경우 에러 발생

C++11의 중괄호 표기법으로 생성 가능

new Point[3]{{0,0}, {0,0}, {0,0}};

하지만 수가 많을 수록 비효율적

메모리 할당과 생성자 호출을 분리하여 해결

Point* p2 = static_cast<Point*>(operator new(sizeof(Point) * 3));

for (int i = 0; i < 3; i++)
{
   	new(&p2[i]) Point(0, 0);
//	std::construct_at(&p2[i], 0, 0);
}

for (int i = 0; i < 3; i++)
{
   	p2[i].~Point();
//	std::destroy_at(&p2[i]);
}

operator delete(p2);
  • vector와 placement new
int main()
{
	std::vector<int> v(10);

	v.resize(7);
	std::cout << v.size() << std::endl; // 7
	std::cout << v.capacity() << std::endl; // 10
    
	v.resize(8);
	std::cout << v.size() << std::endl; // 8
	std::cout << v.capacity() << std::endl; // 10
}

vector의 크기를 줄일 경우 실제 메모리를 줄이지 않고 size 값만 변경

struct X
{
	X()  { std::cout << "X()  get resource"     << std::endl;}
	~X() { std::cout << "~X() release resource" << std::endl;}
};

int main()
{
	std::vector<X> v(10);
    
	v.resize(7); // 소멸자 3번 호출
	v.resize(8); // 생성자 1번 호출
}

메모리의 할당/해지는 발생하지 않지만,
줄어든 객체의 소멸자와 늘어난 객체의 생성자는 명시적으로 호출

profile
주니어 언리얼 프로그래머

0개의 댓글