Reference Counting은 객체의 소유권 관리( = 라이프 사이클 )의 방법 중 하나로 객체를 참조(포인팅) 하고 있는 횟수를 추적하여 그 횟수가 0이 되면 메모리에서 해제(소멸)한다. 대부분의 Managed Language (python, c#, swift등 메모리 관리를 직접 하지 않는 언어 ) 에서 널리 사용되고 있다.
장점
- 메모리를 직접 해제하는 번거로움이 사라진다.
- 객체의 소유권을 공유할 수 있다
- 객체 관리 매커니즘이 비교적 단순해서 빠르다. (Garbage Collection)
단점
- 순환 참조 문제가 있다.
c++ 에서의 구현방식에는 크게 두가지가 있다.
Intrusive Reference Counting (침습성 참조 카운팅)
- 객체에 대한 참조 카운트가 "내장" 되어있다.
- 참조 카운트 매커니즘을 객체가 제공해야한다.
- 메모리사용은 보통 "비침습성"에 비해 작다.
- object 해제시 count 정보도 날아가기 때문에 약한 참조를 구현할 수 없다. (=> 순환참조 문제)
#include <iostream>
class MyObject
{
public:
MyObject(void) : _refCount(0) { std::cout << ":: Initailized!" << std::endl; }
~MyObject(void) { std::cout << ":: Deinitialized!" << std::endl; }
int getCount(void)
{
return _refCount;
}
void addCount(void)
{
++_refCount;
}
void releaseCount(void)
{
if (0 >= --_refCount)
{
delete this;
}
}
private:
int _refCount;
};
template<class Type>
class RefCounted
{
public:
RefCounted(Type* pObject)
: _pObject(pObject)
{
_pObject->addCount();
}
RefCounted(RefCounted<Type>& pObject)
: _pObject(pObject.get())
{
_pObject->addCount();
}
~RefCounted(void)
{
reset();
}
Type* get(void)
{
return _pObject;
}
private:
void reset(void)
{
_pObject->releaseCount();
}
private:
Type* _pObject;
};
int main(void)
{
RefCounted<MyObject> count1(new MyObject);
std::cout << "count1 : " << count1.get()->getCount() << std::endl;
RefCounted<MyObject> count2(count1);
std::cout << "count1 : " << count1.get()->getCount() << std::endl;
std::cout << "count2 : " << count2.get()->getCount() << std::endl;
return 0;
}
:: Initailized!
count1 : 1
count1 : 2
count2 : 2
:: Deinitialized!
non-Intrusive Reference Counting (비침습성 참조 카운팅; c++의 shared_ptr)
- 객체에 대한 참조 카운트를 따로 관리한다.
- 참조 카운트에 대한 포인터가 추가되어 보통 메모리사용이 "침습성"에 비해 크다
- count 정보가 따로 있어 약한 참조를 구현할 수 있다.
#include <iostream>
class MyObject
{
public:
MyObject(void) { std::cout << ":: Initailized!" << std::endl; }
~MyObject(void) { std::cout << ":: Deinitialized!" << std::endl; }
};
template<class Type>
class RefCounted
{
public:
RefCounted(Type* pObject)
: _pObject(pObject)
, _pRefCount(nullptr)
{
addCount();
}
RefCounted(RefCounted<Type>& pObject)
: _pObject(pObject.get())
, _pRefCount(pObject._pRefCount)
{
addCount();
}
~RefCounted(void)
{
reset();
}
Type* get(void)
{
return _pObject;
}
int getCount(void) const
{
return *_pRefCount;
}
private:
void reset(void)
{
if (0 >= releaseCount())
{
delete _pObject;
delete _pRefCount;
}
}
void addCount(void)
{
if (nullptr == _pRefCount)
{
_pRefCount = new int;
(*_pRefCount) = 0;
}
++(*_pRefCount);
}
int releaseCount(void)
{
return --(*_pRefCount);
}
private:
Type* _pObject;
int* _pRefCount;
};
int main(void)
{
RefCounted<MyObject> count1(new MyObject);
std::cout << "count1 : " << count1.getCount() << std::endl;
RefCounted<MyObject> count2(count1);
std::cout << "count1 : " << count1.getCount() << std::endl;
std::cout << "count2 : " << count2.getCount() << std::endl;
return 0;
}
:: Initailized!
count1 : 1
count1 : 2
count2 : 2
:: Deinitialized!
출처: https://nobilitycat.tistory.com/entry/Reference-Counting [고귀양이의 노트.:티스토리]
'프로그래밍 언어 > C++' 카테고리의 다른 글
C++ 스마트 포인터 (Smart Pointer) (0) | 2022.07.26 |
---|---|
C++ 바이트 패딩 (Byte Padding) (0) | 2022.07.26 |
C++ 순환 참조 (Circular Dependency) & 데드락 (0) | 2022.07.24 |
C++ 4가지 타입의 캐스팅 (0) | 2022.07.22 |
C++ 클래스 타입 업/다운 캐스팅 (Up-DownCasting) (0) | 2022.07.22 |