개발자 면접 공부/C-C++

C++ Placement New에 대한 공부

chogyujin 2025. 11. 27. 15:51
728x90

1. 개요

오늘은 C++에 기법인 Placement New에 대해 공부해보도록 하겠습니다.


2. Placement New?

C++에서 placement new는 "이미 할당된 메모리 공간"에 객체를 생성(초기화)하는 문법입니다.

보통의 new 연산자가 [메모리 할당 + 객체 생성]을 동시에 수행한다면, placement new는 할당 단계는 건너뛰고 생성자만 호출하여 객체를 만들어 냅니다.


3. 왜 쓰는가?

주로 성능 최적화정밀한 메모리 제어가 필요한 시스템에서 사용합니다.

  • 메모리 할당 비용 제거: 힙(Heap)에서 메모리를 할당(malloc 등)하는 과정은 운영체제의 시스템 콜을 거치며 시간이 걸립니다. 이를 피하고 싶을 때 사용합니다.
  • 메모리 파편화 방지: 작은 객체를 수없이 생성/삭제하면 메모리가 조각나는데, 미리 큰 메모리 블록(Pool)을 만들어두고 그 안에서 관리하면 이를 방지할 수 있습니다.
  • 하드웨어 제어: 임베디드 시스템 등에서 특정 메모리 주소(예: 하드웨어 레지스터)에 객체를 매핑해야 할 때 사용합니다.

4. 장점

 

  • 속도가 매우 빠름: 메모리 할당 단계가 생략되므로 객체 생성 속도가 획기적으로 빨라집니다.
  • 캐시 적중률(Cache Hit) 향상: 연속된 메모리 공간에 객체들을 배치하면 CPU 캐시 효율이 높아져 처리 속도가 빨라집니다.
  • 재사용성: 할당받은 메모리를 해제하지 않고, 그 자리에 새로운 객체를 덮어씌우는 방식으로 메모리를 재활용할 수 있습니다.

 


5. 주의할 점

이 부분은 시스템의 안정성과 직결되므로 매우 중요합니다.

  1. delete 사용 금지:
    • delete ptr;을 호출하면 안 됩니다. 이 명령어는 메모리 자체를 운영체제에 반환하려 시도하는데, Placement New로 쓴 메모리는 스택이나 정적 영역일 수도 있기 때문에 충돌(Crash)이 발생합니다.
  2. 소멸자의 명시적 호출:
    • 컴파일러가 자동으로 소멸자를 불러주지 않습니다. 객체 사용이 끝나면 반드시 ptr->~ClassName(); 형태로 소멸자를 직접 호출해야 합니다.
  3. 메모리 정렬 (Alignment):
    • 객체가 저장될 메모리 공간은 해당 객체의 정렬 요건(Alignment requirement)을 만족해야 합니다. 그렇지 않으면 버스 에러가 나거나 성능이 저하될 수 있습니다.

6. 예제 코드

#include <iostream>
#include <string>

class User {
public:
    int id;
    std::string name;

    User(int i, std::string n) : id(i), name(n) 
    {
        std::cout << "User 생성자 호출: " << name << std::endl;
    }
    ~User()
    {
        std::cout << "User 소멸자 호출: " << name << std::endl;
    }
};

int main() 
{
    char* buffer = new char[sizeof(User)];

    std::cout << "--- 객체 생성 시작 ---" << std::endl;

    User* userPtr = new (buffer) User(1, "GG");

    std::cout << "ID: " << userPtr->id << ", Name: " << userPtr->name << std::endl;

    std::cout << "--- 객체 사용 종료 ---" << std::endl;

    userPtr->~User();

    return 0;
}

7. 결과

또한, 주소가 char* buffer랑 User가 같다는것을 확인할수 있습니다.


8. 번외

참고로 아래처럼 스택에 할당을 할수 있으니, delete는 안사용하는것이 좋습니다.(소멸자만 호출)

#include <iostream>
#include <string>

class User {
public:
    int id;
    std::string name;

    User(int i, std::string n) : id(i), name(n) 
    {
        std::cout << "User 생성자 호출: " << name << std::endl;
    }
    ~User()
    {
        std::cout << "User 소멸자 호출: " << name << std::endl;
    }
};

int main() 
{
    char buffer[sizeof(User)];

    std::cout << "--- 객체 생성 시작 ---" << std::endl;

    User* userPtr = new (buffer) User(1, "GG");

    std::cout << "ID: " << userPtr->id << ", Name: " << userPtr->name << std::endl;

    std::cout << "--- 객체 사용 종료 ---" << std::endl;

    userPtr->~User();

    return 0;
}

'개발자 면접 공부 > C-C++' 카테고리의 다른 글

정규 표현식  (0) 2025.12.18
정적 링킹 vs 동적 링킹  (0) 2024.07.04
템플릿(Template)  (1) 2024.07.01
C++ 11 범위기반 for문 (for each)  (0) 2024.06.16
extern 쓰는법  (0) 2024.06.11