
std::weak_ptr
개요
std::weak_ptr는 std::shared_ptr가 관리하는 객체에 대한 비소유(non-owning) 참조를 제공하는 스마트 포인터입니다. std::shared_ptr와 달리 std::weak_ptr는 참조 카운트를 증가시키지 않으므로 순환 참조(circular reference) 문제를 해결하는 데 사용됩니다.
C++ 버전별 주요 키워드 도입 시기
- C++11: 
std::weak_ptr가 도입되었습니다. 
내용 설명
std::weak_ptr는 std::shared_ptr 인스턴스를 가리키지만, 해당 객체의 생명 주기에 영향을 주지 않습니다. 즉, std::weak_ptr가 가리키는 객체는 마지막 std::shared_ptr가 소멸될 때 함께 소멸되며, std::weak_ptr는 더 이상 유효하지 않은 객체를 가리키게 됩니다.
주요 멤버 함수는 다음과 같습니다.
expired(): 가리키는 객체가 이미 소멸되었는지 확인합니다.lock():std::weak_ptr가 가리키는 객체를 참조하는 새로운std::shared_ptr를 생성합니다. 만약 객체가 이미 소멸되었다면, 비어있는std::shared_ptr를 반환합니다.use_count(): 객체를 참조하는std::shared_ptr의 개수를 반환합니다. (디버깅 용도로 주로 사용)
std::weak_ptr는 std::shared_ptr만으로 해결할 수 없는 순환 참조 문제를 방지하기 위해 필수적입니다. 두 객체가 서로를 std::shared_ptr로 가리키면 참조 카운트가 0이 되지 않아 메모리 누수가 발생하지만, 한쪽 또는 양쪽을 std::weak_ptr로 바꾸면 이 문제를 해결할 수 있습니다.
예제 코드
#include <iostream>
#include <memory>
#include <string>
class ScopeTest
{
public:
    ScopeTest(int val) : m_val(val)
    {
        std::cout << "Constructor: " << m_val << '\n';
    }
    ~ScopeTest()
    {
        std::cout << "Destructor:" << m_val << '\n';
    }
    void test()
    {
        std::cout << "Val: " << m_val << '\n';
    }
    std::weak_ptr<ScopeTest> m_partner;
    int m_val;
};
void f1()
{
    auto t = std::make_shared<ScopeTest>(1);
    t->test();
    std::cout << "Count: " << t.use_count() << '\n';
    {
        auto t2 = t;
        t2->test();
        std::cout << "Count: " << t.use_count() << '\n';
    }
    std::cout << "Count: " << t.use_count() << '\n';
}
void f2()
{
    auto t4 = std::make_shared<ScopeTest>(11);
    std::cout << "Count t4: " << t4.use_count() << '\n';
    auto t5 = std::make_shared<ScopeTest>(12);
    std::cout << "Count t5: " << t5.use_count() << '\n';
    t4->m_partner = t5;
    std::cout << "Count t5: " << t5.use_count() << '\n';
    t5->m_partner = t4;
    std::cout << "Count t4: " << t4.use_count() << '\n';
    if (!t4->m_partner.expired())
    {
        auto t4_partner_shard = t4->m_partner.lock();
        std::cout << t4_partner_shard->m_val << std::endl;
        std::cout << "Count t5: " << t5.use_count() << '\n';
    }
}
int main()
{
    f1();
    std::cout << '\n';
    f2();
    return 0;
}
실행 결과
Constructor: 1
Val: 1
Count: 1
Val: 1
Count: 2
Count: 1
Destructor:1
Constructor: 11
Count t4: 1
Constructor: 12
Count t5: 1
Count t5: 1
Count t4: 1
12
Count t5: 2
Destructor:12
Destructor:11
활용팁
- 순환 참조 방지: 
std::weak_ptr의 가장 중요한 용도입니다. 클래스들이 서로를std::shared_ptr로 참조해야 할 때, 한쪽을std::weak_ptr로 만들어 순환 참조를 끊고 메모리 누수를 방지할 수 있습니다. - 캐시(Cache) 구현: 객체에 대한 참조가 필요하지만, 해당 객체의 수명을 연장하고 싶지 않을 때 유용합니다. 캐시된 객체가 다른 곳에서 더 이상 사용되지 않아 소멸되면, 캐시는 
expired()를 통해 이를 감지하고 무효한 참조를 제거할 수 있습니다. - 안전한 접근: 
lock()함수를 통해std::shared_ptr를 얻은 후 객체에 접근하면, 다중 스레드 환경에서도 객체가 접근 도중에 소멸되는 것을 방지하여 안전하게 사용할 수 있습니다. 
'개발 > C++ (98,03,11,14,17,20,23)' 카테고리의 다른 글
| Modern C++ : std::shared_timed_mutex (14) (0) | 2025.10.19 | 
|---|---|
| Modern C++ : std::mutex (11, 14, 17) (1) | 2025.10.18 | 
| Modern C++ : std::thread (11) (0) | 2025.10.17 | 
| Modern C++ : std::exception (98, 11, 17) (0) | 2025.10.16 | 
| Modern C++ : std::shared_ptr (11, 17) (0) | 2025.10.14 | 
| Modern C++ : std::unique_ptr (11, 14) (0) | 2025.10.13 | 
| Modern C++ : std::format (20) (0) | 2025.10.12 | 
| Modern C++ : std::ranges (20) (0) | 2025.10.11 |