debug모드일 때, 동작하며 프로그래머의 실수 탐지용으로 자주 사용된다.
_ASSERT() 내부에는 true인 조건만 들어가야 하며,
조건이 false일때 실행되면 에러를 띄운다.
c++에서 메모리관리를 효율적으로 하게 해주는 포인터.
적절한 시점에 자동으로 메모리를 해제하여 메모리 누수를 방지할 수 있다.
소유권이 하나만 존재하는 포인터로, 소멸자 호출시 즉시 메모리를 해제한다.
new() 를 통해 생성할 수 있지만,
std::make_unique()함수를 통해 간단히 생성할 수 있다.
unique_ptr<int> Unique = make_unique<int>();
*Unique =100;
다른 unique_ptr에게 대입할 수 없다.
unique_ptr<int> Unique2 = Unique;
바로 에러가 뜬다.
하지만 소유권을 이전시켜 줄 수 있다.
unique_ptr<int> Unique2 = std::move(Unique);
move함수를 이용해 이전 시켜준 후,
기존 포인터 Unique에는 nullptr로 잡힌다.
만약 다른 함수에서 일시적으로 unique_ptr에 접근하려고 한다면 .get 함수를 통해
주소값을 반환할 수 있다.
함수 parameter로 unique ptr을 전달하려고 한다면
void TestUnique(std::unique_ptr<int>* OutUnique)
{
**OutUnique = 100;
}
이런식으로 unique_ptr의 주소를 전달하면 된다.
단 unique_ptr의 주소를 전달하므로 실제 참조값을 사용하려면 역참조를 두번해야한다.
아니면
void TestUnique(int* OutUnique)
{
*OutUnique = 100;
}
이렇게 구현 후,
unique_ptr<int> Unique = make_unique<int>(100);
TestUnique(Unique.get());
이런식으로 해당 함수 내부에서는 unique_ptr이 아닌 그냥 포인터로 접근해 사용하게 구현할 수 있다.
레퍼런스를 카운트 하는 포인터로, 해당 포인터에 대해 레퍼런스 카운트가 0이 될때 메모리 해제되는 스마트포인터다.
//heap에서 reference count 가지고 있음
shared_ptr <int> Shared = make_shared<int>(100);
//대입시 referenceCount +1 되며 관리
shared_ptr<int> Shared2 = Shared;
//SHared가 해제 되면 reference Count 1되고, shared2해제 되면 0되면서 메모리 해제시킴
long Count = Shared.use_count();
unique_ptr과 마찬가지로 make_shared함수를 통해 간편히 생성할 수 있고,
인자가 있다면 전달해서 초기화시킬 수 있다.
shared_ptr<int> Shared2 = Shared;
이렇게 새 shared_ptr에 기존 shared_ptr을 대입시 reference count가 1 증가한다.
use_count();
라는 함수를 통해 현재 reference_count를 확인할 수 있다.
unique_ptr과 마찬가지로 shared_ptr도 .get() 함수를 지원해 주소를 받아올 수 있다.
여기서 .get()으로 받아온 해당 포인터를 shared_ptr로 다시 만들어줄 수 있는데,
해당 구조체나 클래스에 아래 클래스를 상속시키면 된다.
struct FSharedTest : public std::enable_shared_from_this<FSharedTest>
{
FSharedTest(){}
FSharedTest(int lnA): A(lnA){}
int A = 100;
};
여기선 임시 구조체 FSharedTest에 상속받아서 구현했다.
그러면 .get()으로 받아온 해당 포인터에서 shared_from_this()함수를 이용해
shared_ptr을 생성해줄 수 있다.
FSharedTest* Test = Shared.get();
shared_ptr<FSharedTest> SharedTest = Test->shared_from_this();
또한 shared_ptr에는 reset이라는 함수를 제공하는데,
이 함수는 전체 shared_ptr을 제거하는 것이 아닌 해당 인스턴스의 참조만 제거한다.
SharedTest.reset();
Shared= nullptr;
nullptr로 초기화시키는것과 동일하므로 , shared_ptr의 참조가 여러개라면
한 인스턴스에 reset을 썼다고 모든 참조가 끊기고 delete되는 게 아니다!
weak_ptr은 참조하는 포인터처럼 사용할 수 있지만 기본적으로 참조 횟수를 늘려주지 않는 포인터다.
// 참조하는 포인터가 댕글링 포인터가 되었는지 확인 가능.
weak_ptr<FParam> Weak;
{
shared_ptr<FParam> shared = make_shared<FParam>();
shared_ptr<FParam> shared2 = shared;
Weak = shared;
}
위처럼 shared_ptr의 참조를 두개를 만들고 해당 shared_ptr을 weak_ptr에 연결해준다.
이렇게 되면 shared_ptr의 강한 참조는 두개가 생기고 약한 참조는 1개가 생긴다.
weak_ptr의 약한참조는 연결된 shared_ptr의 강한 참조에 영향을 주지 않는다.
따라서 weak_ptr은 shared_ptr이 더 이상 참조되고 있는지 여부를 검사할 수 있다.
위 block을 빠져나오는 순간 shared는 메모리에서 해제되었지만
weak_ptr은 여전히 shared를 가리키고, weak_ptr이 제공하는 expired()함수를 통해
가리키고 있는 shared_ptr이 메모리 해제되었는지 여부를 알 수가 있다.
weak_ptr이 가리키는 shared_ptr은 lock()함수를 통해 안전하게 받아올 수 있다.
"안전하게" 라는 뜻은 만약 shared_ptr이 메모리 해제된 상태라면
nullptr을 받아와 에러를 일으키지 않는다.