개요
C++ 스마트 포인터 shared_ptr의 참조 카운트가 0이 되어도 weak_ptr이 참조하고 있다면 메모리를 해제하지 않고 소멸자만 부른다.
스마트 포인터 간단 요약

스마트 포인터의 기본 원리는
make_shared시에, control block(스마트 포인터 관리용 오브젝트)와 object(실제 사용하는 오브젝트)가 생성된다.
이후 shared_ptr이 참조할 때마다 use_count가 늘어나고,
weak_ptr이 참조할 때 마다 weak_count가 늘어난다.
use_count가 0이 되면 object의 소멸자가 호출되고,
모든 count가 0이 되면 control block과 object의 메모리가 해제된다.
메모리 해제 시점
상식적으로 use_count가 0이 될 때, object의 메모리를 해제해야 하는 것 아닌가?
하지만 그렇지 않다. 실험을 해보자.
#include <memory>
#include <iostream>
#include <string>
class A{
public:
int number;
};
int main(int argc, const char * argv[])
{
A* ptr_a = nullptr;
// std::weak_ptr<A> weak_ptr_a;
{
std::shared_ptr<A> shared_ptr_a = std::make_shared<A>();
shared_ptr_a->number = 500;
ptr_a = shared_ptr_a.get();
// weak_ptr_a = shared_ptr_a;
}
// 주석을 설정하면 My number is 0
// 주석을 해제하면 My number is 500
std::cout << "My number is " << ptr_a->number << std::endl;
return 0;
}
이렇게 weak_ptr 유무에 따라서 결과가 달라지는 것을 볼 수있다.


위와 같이 visual studio memory debugging에서도 메모리 사용 여부가 잡힌다.
코드 검증
make_shared 단

실제로 make_shared시에 생성되는 _Ref_count_obj2에는 _Ty를 포인터가 아닌 멤버 변수로 바로 만들고 있어서 따로 해제할 수 있는 방법이 없다.
use count 감소 처리단



위 코드를 근거로 use count가 0이되어도 _Obj.~_Ty() 즉 소멸자 호출만 일어나고 메모리 해제는 따로 일어나지 않는 것을 알 수 있다.
weak count 감소 처리단


weak count가 0이 될 경우 컨트롤 블록이 delete 되며 멤버 변수로 생성되어 있는 object도 같이 해제되는 모습이다.
왜 그럴까?
왜 저렇게 설계하였는지 명확한 이유는 찾기 힘들지만, Windows/MacOS에서는 그렇게 작동하는 것을 확인하였으며 control block과 object를 같은 메모리 위치에 할당하고 두 객체를 항상 동시에 생성 및 해제시키려고 그렇게 만든 것으로 추정된다.
'Programming > C++ & Unreal' 카테고리의 다른 글
메모리 파편화 + boost, tbb 도구 (0) | 2025.03.30 |
---|---|
vprintf, vsprintf 등 가변 인자 함수를 활용한 로그 함수 개발 시에 포맷 warning 출력하기 (0) | 2024.04.05 |
StackWalk64가 context에 의하여 Access violation를 유발 (1) | 2023.10.23 |
C++ 가변인자(va_list)를 오버로딩 하지 말자. (1) | 2023.10.23 |
C++ parallel for_each (thread) exception (1) | 2023.10.23 |
개요
C++ 스마트 포인터 shared_ptr의 참조 카운트가 0이 되어도 weak_ptr이 참조하고 있다면 메모리를 해제하지 않고 소멸자만 부른다.
스마트 포인터 간단 요약

스마트 포인터의 기본 원리는
make_shared시에, control block(스마트 포인터 관리용 오브젝트)와 object(실제 사용하는 오브젝트)가 생성된다.
이후 shared_ptr이 참조할 때마다 use_count가 늘어나고,
weak_ptr이 참조할 때 마다 weak_count가 늘어난다.
use_count가 0이 되면 object의 소멸자가 호출되고,
모든 count가 0이 되면 control block과 object의 메모리가 해제된다.
메모리 해제 시점
상식적으로 use_count가 0이 될 때, object의 메모리를 해제해야 하는 것 아닌가?
하지만 그렇지 않다. 실험을 해보자.
#include <memory>
#include <iostream>
#include <string>
class A{
public:
int number;
};
int main(int argc, const char * argv[])
{
A* ptr_a = nullptr;
// std::weak_ptr<A> weak_ptr_a;
{
std::shared_ptr<A> shared_ptr_a = std::make_shared<A>();
shared_ptr_a->number = 500;
ptr_a = shared_ptr_a.get();
// weak_ptr_a = shared_ptr_a;
}
// 주석을 설정하면 My number is 0
// 주석을 해제하면 My number is 500
std::cout << "My number is " << ptr_a->number << std::endl;
return 0;
}
이렇게 weak_ptr 유무에 따라서 결과가 달라지는 것을 볼 수있다.


위와 같이 visual studio memory debugging에서도 메모리 사용 여부가 잡힌다.
코드 검증
make_shared 단

실제로 make_shared시에 생성되는 _Ref_count_obj2에는 _Ty를 포인터가 아닌 멤버 변수로 바로 만들고 있어서 따로 해제할 수 있는 방법이 없다.
use count 감소 처리단



위 코드를 근거로 use count가 0이되어도 _Obj.~_Ty() 즉 소멸자 호출만 일어나고 메모리 해제는 따로 일어나지 않는 것을 알 수 있다.
weak count 감소 처리단


weak count가 0이 될 경우 컨트롤 블록이 delete 되며 멤버 변수로 생성되어 있는 object도 같이 해제되는 모습이다.
왜 그럴까?
왜 저렇게 설계하였는지 명확한 이유는 찾기 힘들지만, Windows/MacOS에서는 그렇게 작동하는 것을 확인하였으며 control block과 object를 같은 메모리 위치에 할당하고 두 객체를 항상 동시에 생성 및 해제시키려고 그렇게 만든 것으로 추정된다.
'Programming > C++ & Unreal' 카테고리의 다른 글
메모리 파편화 + boost, tbb 도구 (0) | 2025.03.30 |
---|---|
vprintf, vsprintf 등 가변 인자 함수를 활용한 로그 함수 개발 시에 포맷 warning 출력하기 (0) | 2024.04.05 |
StackWalk64가 context에 의하여 Access violation를 유발 (1) | 2023.10.23 |
C++ 가변인자(va_list)를 오버로딩 하지 말자. (1) | 2023.10.23 |
C++ parallel for_each (thread) exception (1) | 2023.10.23 |