RefCounting부분
#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <atomic>
#include <mutex>
#include <windows.h>
#include <future>
#include "ThreadManager.h"
#include "RefCounting.h"
#pragma once
/*---------------
RefCountable
----------------*/
class RefCountable
{
public:
RefCountable() : _refCount(1) { }
virtual ~RefCountable() { }
int32 GetRefCount() { return _refCount; }
int32 AddRef() { return ++_refCount; }
int32 ReleaseRef()
{
int32 refCount = --_refCount;
if (refCount == 0)
{
delete this;
}
return refCount;
}
protected:
atomic<int32> _refCount;
};
/*---------------
SharedPtr
----------------*/
template<typename T>
class TSharedPtr
{
public:
TSharedPtr() { }
TSharedPtr(T* ptr) { Set(ptr); }
// 복사
TSharedPtr(const TSharedPtr& rhs) { Set(rhs._ptr); }
// 이동
TSharedPtr(TSharedPtr&& rhs) { _ptr = rhs._ptr; rhs._ptr = nullptr; }
// 상속 관계 복사
template<typename U>
TSharedPtr(const TSharedPtr<U>& rhs) { Set(static_cast<T*>(rhs._ptr)); }
~TSharedPtr() { Release(); }
public:
// 복사 연산자
TSharedPtr& operator=(const TSharedPtr& rhs)
{
if (_ptr != rhs._ptr)
{
Release();
Set(rhs._ptr);
}
return *this;
}
// 이동 연산자
TSharedPtr& operator=(TSharedPtr&& rhs)
{
Release();
_ptr = rhs._ptr;
rhs._ptr = nullptr;
return *this;
}
bool operator==(const TSharedPtr& rhs) const { return _ptr == rhs._ptr; }
bool operator==(T* ptr) const { return _ptr == ptr; }
bool operator!=(const TSharedPtr& rhs) const { return _ptr != rhs._ptr; }
bool operator!=(T* ptr) const { return _ptr != ptr; }
bool operator<(const TSharedPtr& rhs) const { return _ptr < rhs._ptr; }
T* operator*() { return _ptr; }
const T* operator*() const { return _ptr; }
operator T* () const { return _ptr; }
T* operator->() { return _ptr; }
const T* operator->() const { return _ptr; }
bool IsNull() { return _ptr == nullptr; }
private:
inline void Set(T* ptr)
{
_ptr = ptr;
if (ptr)
ptr->AddRef();
}
inline void Release()
{
if (_ptr != nullptr)
{
_ptr->ReleaseRef();
_ptr = nullptr;
}
}
private:
T* _ptr = nullptr;
};
Knight class
using KnightRef = TSharedPtr<class Knight>;
class Knight : public RefCountable
{
public:
Knight()
{
cout << "Knight()" << endl;
}
~Knight()
{
cout << "~Knight()" << endl;
}
void SetTarget(KnightRef target)
{
_target = target;
}
public:
KnightRef _target = nullptr;
};
오류가 발생하지 않는 상황
int main()
{
KnightRef k1(new Knight());
k1->ReleaseRef();
KnightRef k2(new Knight());
k2->ReleaseRef();
k1->SetTarget(k2);
k1 = nullptr;
k2 = nullptr;
return 0;
}
- 여기서는 k1이 nullptr로 되면 가지고 있던 k2도 하나 사라지면서 오류 없이 작동한다.
순환이 발생하는 순간
KnightRef k1(new Knight());
k1->ReleaseRef();
KnightRef k2(new Knight());
k2->ReleaseRef();
k1->SetTarget(k2);
k2->SetTarget(k1);
k1 = nullptr;
k2 = nullptr;
- 이상황에서는 k1이 맴버변수로 k2까지 들고있고 k2도 k1을 맴버변수로 들고 있어서
int32 ReleaseRef()
{
int32 refCount = --_refCount;
if (refCount == 0)
{
delete this;
}
return refCount;
}
- ReleaseRef부분에서 사용을 하지않아도 refCount가 0이 되지않아서 delete가 되지않는다 순환 문제가 발생하는 것이다. (데드락과 비슷한..) 그래서
k1->SetTarget(nullptr);
k2->SetTarget(nullptr);
- 위 부분처럼 주시대상을 nullptr로 만드는 작업도 해야한다.
unique_ptr
- unique_ptr은 간단하다, 하나의 독자전인 포인터를 들고있겠다는 것이고 또한 복사가 금지 되어있어서 복사 대신 move로 해야한다
//unique_ptr -> 복사가 금지되어있다.
unique_ptr<Knight> k2 = make_unique<Knight>();
unique_ptr<Knight> k3 = std::move(k2);
- 해당영역이 복사가 금지되어있는 것이다 unique_ptr의 내부 자료
shared_ptr
- shared_ptr내부를 보면 _Ptr_base를 상속 받고 있다. _Ptr_base는 맴버 변수 (참고로 _Ptr_base는 shared_ptr와 weak_ptr모두 상속 받고있다)
private:
element_type* _Ptr{nullptr};
_Ref_count_base* _Rep{nullptr};
- 위의 2가지를 가지고있다. [T][RefCountingBlock] 이라고 생각하면된다. 내가 가리키고 있는 포인터랑, 참조하고있는 RefCounting수이다.
shared_ptr weak_ptr이 상속받고있는 ptr_base에서 가지고 있는 Refcount
RefCount를 보면 uses랑 weaks를 가지고 있다.
[Knight][RefCountingBlock(uses, weak두가지가 있다)]
shared_ptr는 다 사용했으면 uses를 감소하고, Kinght를 해제하는데 weak_ptr은 RefCountingBlock에만 관여를 하고 바라보는 대상에는 상관하지않는다.. 그래서 순환문제를 막을 수 있지만 weak_ptr을 사용할려면 expired로 있는지 체크를 한후 사용하는 것이 번거롭다.
bool expired = wpr.expired();
shared_ptr<Knight> spr3 = wpr.lock();
if (spr3 != nullptr)
{
}
'메모리관리(스마트포인터...)' 카테고리의 다른 글
stompAllocator, 가상메모리 (0) | 2022.04.10 |
---|---|
stompAllocator (0) | 2022.04.07 |
Allocator (0) | 2022.04.07 |
ReferenceCounting(스마트포인에 전..) (0) | 2022.03.31 |