(C++) weak_ptr

Posted by : at

Category : Cpp


언제쓰나

  • 참조변수가 증가하지 않는 스마트 포인터가 필요하다.
  • 원본 객체가 파괴되었을 시 다 같이 삭제 되는 스마트 포인터가 필요하다.

shared_ptr의 문제

#include <iostream>
#include <string>
#include <memory>
using namespace std;

struct People
{
    People(string s) : name(s) {}
    ~People() { cout << "~People : " << name << endl; }

    string name;
    shared_ptr<People> bf;  // best friend
};

int main()
{
    shared_ptr<People> p1(new People("Kim"));
    shared_ptr<People> p2(new People("Lee"));

    p1->bf = p2;
    p2->bf = p1;
    // 자원이 파괴되지 않는다.
    // 서로가 서로를 가르키게 된다.
}

참조변수가 증가하지 않는 포인터가 필요하다 -> weak_ptr

#include <iostream>
#include <string>
#include <memory>
using namespace std;

struct People
{
    People(string s) : name(s) {}
    ~People() { cout << "~People : " << name << endl; }

    string name;
    weak_ptr<People> bf;  
    // 참조변수가 증가하지 않는 포인터가 필요
    // 또한 원본 객체가 파괴되었는지 알수도 있다!!
};

share_ptr 참조객체 개수 알아보기

#include <iostream>
#include <memory>
using namespace std;

class Car
{
    int color;
    int speed;
public:
    ~Car() { cout << "~Car()" << endl; }
 
    void Go() { cout << "Car go" << endl; }
};

int main()
{
    shared_ptr<Car> wp; // use count 증가
    shared_ptr<Car> sp(new Car);
    wp = sp;

    cout << sp.use_count() << endl; // 2

weak_ptr 써보기

int main()
{
    weak_ptr<Car> wp; // use count 증가 X
    
    {
        shared_ptr<Car> sp(new Car);
        wp = sp;

        cout << sp.use_count() << endl; // 1
    }

    if( wp.expired() )      // 원본 객체가 파괴되었는지 확인 가능
        cout << "destory" << endl;
    else
        cout << "not destory" << endl;
int main()
{
    weak_ptr<Car> wp; // use count 증가 X
    
    //{
        shared_ptr<Car> sp(new Car);
        wp = sp;

        cout << sp.use_count() << endl; // 1
    //}

    if( wp.expired() )
        cout << "destory" << endl;
    else {
        cout << "not destory" << endl;
        wp->Go();       // error - weak_ptr은 대상 객체에 접근 불가
        // 이유는 use_count를 쓰지 않기에 다른곳에서 모르고 삭제를 해 버릴수 있다. 그런 실수를 방지하기 위해서 weak_ptr은 직접접근 불가

        // weak_ptr을 가지고 다시 shared_ptr을 만들어야한다.
    }
shared_ptr<Car> sp2 = wp.lock();

if(sp2)
    sp->Go();

Example

class Dog {
    shared_ptr<Dog> m_pFriend;
public:
    string m_name;
    void bark() { cout << "Dog" << m_name << " rules!" << endl; }
    Dog() { //create }
    ~Dog() { cout << "dog is destroyed: " << m_name << endl; }
    void makeFriend(shared_ptr<Dog> f) { m_pFriend = f; }
};

int main()
{
    shared_ptr<Dog> pD(new Dog("Gunner"));
    shared_ptr<Dog> pD(new Dog("Smokey"));
    pD->makeFriend(pD2);
    pD->makeFriend(pD);
    // 서로 물고있어 삭제가 되지 않음.
    // cyclic reference
}
class Dog {
    weak_ptr<Dog> m_pFriend;        // 해결
    // 사실 weak_ptr은 raw pointer(Dog *) 사용과 동일하다 단, weak_ptr로 delete를 할 수 없다는 점만 다르다
public:
    string m_name;
    void bark() { cout << "Dog" << m_name << " rules!" << endl; }
    Dog() { //create }
    ~Dog() { cout << "dog is destroyed: " << m_name << endl; }
    void makeFriend(shared_ptr<Dog> f) { m_pFriend = f; }
};
// weak_ptr은 그냥 사용하면 안된다.
class Dog {
    weak_ptr<Dog> m_pFriend;
public:
    string m_name;
    void bark() { cout << "Dog" << m_name << " rules!" << endl; }
    Dog() { //create }
    ~Dog() { cout << "dog is destroyed: " << m_name << endl; }
    void makeFriend(shared_ptr<Dog> f) { m_pFriend = f; }
    void showFriend() {
        if(!m_pFriend.expired()) {
            cout << "My friend is : " << m_pFriend.lock()->m_name << endl;
            cout << m_pFriend.use_count() << endl;
        }
    }
};

About Taehyung Kim

안녕하세요? 8년차 현업 C++ 개발자 김태형이라고 합니다. 😁 C/C++을 사랑하며 다양한 사람과의 협업을 즐깁니다. ☕ 꾸준한 자기개발을 미덕이라 생각하며 노력중이며, 제가 얻은 지식을 홈페이지에 정리 중입니다. 좀 더 상세한 제 이력서 혹은 Private 프로젝트 접근 권한을 원하신다면 메일주세요. 😎

Star
Useful Links