29. placement new와 수동 소멸자 호출(객체 라이프타임 관리)
난이도 최상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C++
// ============================================================================
// [언어 내부동작 문제] C++ - placement new와 수동 소멸자 호출(객체 라이프타임 관리)
// ----------------------------------------------------------------------------
// 주제: "메모리 할당"과 "객체 생성"은 왜 별개의 단계인가?
// - 게임서버에서 흔한 패턴: 매 틱(tick)마다 짧게 사는 이벤트/패킷 객체를
// new/delete 하면 힙 할당 오버헤드가 크다. 그래서 큰 버퍼를 한 번만 할당해두고
// 그 위에서 객체를 반복적으로 생성/파괴하는 "오브젝트 풀"을 직접 구현하곤 한다.
//
// 과제:
// 1) 아래 main 의 출력을 예측하라. 특히 두 번째 슬롯 재사용 시 생성자가 다시
// 호출되는지, 그리고 Pool 소멸 시 몇 개의 소멸자가 호출되는지 예측하라.
// 2) `::operator new(sizeof(Session))` 와 `new (ptr) Session(...)` (placement new)
// 가 각각 어떤 일을 하는지, 왜 둘을 분리해야 오브젝트 풀을 만들 수 있는지
// 설명하라.
// 3) `p->~Session()` 처럼 소멸자를 명시적으로 호출하는 것과 `delete p` 의 차이를
// 설명하라(메모리 해제 여부, 이후 그 메모리를 재사용하는 것이 안전한 이유).
// 4) 이 패턴에서 흔히 발생하는 실수(이중 소멸, 소멸 안 한 채 메모리 재사용,
// 정렬(alignment) 무시)를 설명하라.
// (먼저 직접 예측·설명을 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
#include <cstdio>
#include <cstddef>
#include <new>
class Session {
public:
explicit Session(int id) : id_(id) {
std::printf("Session(%d) 생성\n", id_);
}
~Session() {
std::printf("Session(%d) 소멸\n", id_);
}
void Greet() const {
std::printf("Session(%d) 인사\n", id_);
}
private:
int id_;
};
// 슬롯 2개짜리 아주 단순한 고정 크기 오브젝트 풀
class SessionSlot {
public:
SessionSlot() : storage_(), alive_(false) {}
Session* Acquire(int id) {
// (A) 이미 살아있는 객체가 있다면?
Session* p = reinterpret_cast<Session*>(&storage_);
p = new (p) Session(id); // placement new: 이 자리에 생성
alive_ = true;
return p;
}
void Release() {
if (alive_) {
Session* p = reinterpret_cast<Session*>(&storage_);
p->~Session(); // (B) 명시적 소멸자 호출
alive_ = false;
}
}
~SessionSlot() {
Release();
}
private:
alignas(Session) unsigned char storage_[sizeof(Session)];
bool alive_;
};
int main() {
SessionSlot slot;
Session* s1 = slot.Acquire(1);
s1->Greet();
slot.Release();
// 같은 메모리 위치를 재사용해 새 객체를 생성
Session* s2 = slot.Acquire(2);
s2->Greet();
std::printf("main 끝, slot 소멸 예정\n");
return 0;
} 내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.