3. shared_ptr 제어블록, 순환 참조, weak_ptr

난이도 상 해설 보기 →

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

결함 코드 · C++
// ============================================================================
// [언어 내부동작 문제] C++ - shared_ptr 제어블록, 순환 참조, weak_ptr
// ----------------------------------------------------------------------------
// 주제:
//   std::shared_ptr 의 제어블록(control block)과 (원자적) 참조계수, weak_ptr 가
//   강한 계수를 올리지 않는다는 점, enable_shared_from_this, 그리고 서로를 shared_ptr
//   로 가리키는 순환 참조가 일으키는 누수.
//
// 과제:
//   1) 아래 프로그램의 출력을 예측하라. 특히 각 use_count 값과, 끝에서 어떤 객체의
//      소멸자(dtor)가 호출되고 어떤 것이 "호출되지 않는지"를 정확히 적어라.
//   2) weak_ptr 가 use_count 에 어떤 영향을 주는지, shared_from_this 가 use_count 를
//      어떻게 바꾸는지 설명하라.
//   3) 끝에서 회수되지 못하는(소멸자가 불리지 않는) 객체가 있다면 무엇이고, 그 이유를
//      제어블록/참조계수 관점에서 설명한 뒤, 이를 weak_ptr 로 어떻게 고치는지 제시하라.
//   (먼저 직접 예측·설명을 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

#include <iostream>
#include <memory>
#include <string>
#include <utility>

struct Node : std::enable_shared_from_this<Node>
{
    std::string           name;
    std::shared_ptr<Node> next;   // 강한 참조
    Node(std::string n) : name(std::move(n)) { std::cout << "ctor " << name << "\n"; }
    ~Node() { std::cout << "dtor " << name << "\n"; }
};

int main()
{
    auto a = std::make_shared<Node>("A");
    std::cout << "a.use_count=" << a.use_count() << "\n";

    std::weak_ptr<Node> w = a;
    std::cout << "after weak, a.use_count=" << a.use_count() << "\n";

    {
        std::shared_ptr<Node> b = a;
        std::cout << "in block, a.use_count=" << a.use_count() << "\n";
    }
    std::cout << "after block, a.use_count=" << a.use_count() << "\n";

    auto x = std::make_shared<Node>("X");
    auto y = std::make_shared<Node>("Y");
    x->next = y;
    y->next = x;
    std::cout << "x.use_count=" << x.use_count()
              << ", y.use_count=" << y.use_count() << "\n";

    auto self = x->shared_from_this();
    std::cout << "x.use_count after shared_from_this=" << x.use_count() << "\n";
    self.reset();

    std::cout << "end of main\n";
    return 0;
}
내 리뷰 · C++
내 답안 · 자동 저장

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