22. 멤버 초기화 리스트의 실행 순서

난이도 중 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C++
// ============================================================================
// [언어 내부동작 문제] C++ - 멤버 초기화 리스트의 실행 순서
// ----------------------------------------------------------------------------
// 주제: 생성자의 멤버 초기화 리스트(member-init-list)에 나열한 순서와,
//   실제로 멤버가 초기화되는 순서가 항상 같을까?
//   - 이 문제는 "결함을 고치는" 문제가 아니라, C++ 의 동작 원리를 설명하는 문제다.
//   - 게임서버 코드에서 흔한 패턴: 세션/엔티티 클래스가 여러 멤버를 두고, 한 멤버의
//     초기값이 다른 멤버의 값에 의존하도록 초기화 리스트를 작성한다.
//
// 과제:
//   1) 아래 main 의 출력을 예측하라(어떤 순서로 어떤 값이 출력되는지).
//   2) 왜 그런 순서가 되는지, 무엇이 "실제로" 초기화 순서를 결정하는지 설명하라.
//   3) 아래 코드를 컴파일할 때 컴파일러가 경고를 낸다면 어떤 경고이고, 그 경고가
//      가리키는 위험은 무엇인지 설명하라.
//   4) 소멸자가 여러 개 있을 때 소멸 순서는 초기화 순서와 어떤 관계인지 설명하라.
//   (먼저 직접 예측·설명을 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

#include <cstdio>

class PacketBuffer {
public:
    // 멤버 초기화 리스트에는 size_ 를 먼저, capacity_ 를 나중에 적었다.
    // 그런데 size_ 의 초기값이 capacity_ 를 참조하도록 작성돼 있다. (A)
    PacketBuffer(int capacity)
        : size_(capacity_ / 2)   // capacity_ 를 참조해서 size_ 를 정한다
        , capacity_(capacity)    // (B) 선언 순서와 리스트 작성 순서를 비교해볼 것
    {
        std::printf("capacity_=%d, size_=%d\n", capacity_, size_);
    }

    ~PacketBuffer() {
        std::printf("~PacketBuffer (capacity_=%d)\n", capacity_);
    }

private:
    // 선언 순서: size_ 가 capacity_ 보다 먼저 선언되어 있다.
    int size_;
    int capacity_;
};

class Session {
public:
    Session(int cap)
        : id_(1)
        , buf_(cap)
        , name_("session")
    {
        std::printf("Session ctor done: id=%d, name=%s\n", id_, name_);
    }

    ~Session() {
        std::printf("~Session\n");
    }

private:
    int id_;
    PacketBuffer buf_;
    const char* name_;
};

int main() {
    std::printf("--- constructing Session ---\n");
    Session s(64);
    std::printf("--- destructing Session ---\n");
    return 0;
}
내 리뷰 · C++
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.