https://younggwan.tistory.com/36

윗 글에서 std::shared_ptr 의 정의와 문제점에대한 정리를 했는데. 
std::shared_ptr의 문제점이 였던 순환 참조 문제를 해결할 수 있는 std::weak_ptr을 정리해 봅시다.

정의

weak_ptr은 하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대한 접근을 제공하지만, 소유자의 수에는 포함되지 않는 스마트 포인터입니다.

shared_ptr은 참조 횟수(reference count)를 기반으로 동작하는 스마트 포인터입니다.

만약 서로가 상대방을 가리키는 shared_ptr를 가지고 있다면, 참조 횟수는 절대 0이 되지 않으므로 메모리는 영원히 해제되지 않습니다.

이렇게 서로가 상대방을 참조하고 있는 상황을 순환 참조(circular reference)라고 합니다.

weak_ptr은 바로 이러한 shared_ptr 인스턴스 사이의 순환 참조를 제거하기 위해서 사용됩니다.

멤버 함수

reset : 관리 객체의 소유권을 공개 합니다.
swap : 관리 객체를 교환합니다.
use_count : shared_ptr개체를 관리하는 개체 수를 반환합니다.
expired : 참조된 객체가 삭제되었는지 확인합니다.
lock : shared_ptr로 변환 해서 참조할 수 있게 합니다.(변환이 맞는지는 모르겠습니다)
owner_before : 약한 포인터의 소유자 기반 순서를 제공합니다.


사용 예제

#include <iostream>

#include <memory>


class TestClass

{

public:

std::string name;

std::weak_ptr<TestClass> m_Other_Class;

void TestFunc()

{

std::cout << "hahaha" << std::endl;

}


void Set_Class(std::weak_ptr<TestClass> _Value)

{

m_Other_Class = _Value;

}


void Access_Other_Class()

{

std::shared_ptr<TestClass> convert_weak_ptr = m_Other_Class.lock();

if (convert_weak_ptr)

{

std::cout << this->name.c_str() << " 접근 성공 -> " << convert_weak_ptr->name.c_str() <<std::endl;

}

else

{

std::cout << "접근 실패" << std::endl;

}

}


TestClass(std::string _name) : name(_name)

{

std::cout << this->name.c_str() <<" 생성자 호출" << std::endl;

}

~TestClass()

{

std::cout << this->name.c_str() << " 소멸자 호출" << std::endl;

}

};


int main()

{

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

std::shared_ptr<TestClass> T_A = std::make_shared<TestClass>("A클래스");

std::shared_ptr<TestClass> T_B = std::make_shared<TestClass>("B클래스");

T_A->Set_Class(T_B);

T_B->Set_Class(T_A);

T_A->Access_Other_Class();

T_B->Access_Other_Class();

T_B.reset();

T_A->Access_Other_Class();

}


결과

A클래스 생성자 호출
B클래스 생성자 호출
A클래스 접근 성공 -> B클래스
B클래스 접근 성공 -> A클래스
B클래스 소멸자 호출
접근 실패
A클래스 소멸자 호출

순환 참조의 소멸자 호출이 없어서 릭이 남던 문제가 없어지고 정상적으로 작동을 한다.

+ Recent posts