오전 1시간동안 코드카타를 하는데 아직 그럴 실력이 안돼서 일단 문법 공부를 더 해보려고한다.
19일 작성한 RAII 패턴 기반의 포인터 래퍼이다.
사용하는 목적은 수동으로 해주던 new/delete의 할당/해제를 자동으로 해준다. 또한 소유권을 명확하게 하는데 의의가 있다.
일반 포인터는 주소를 담고 있다는 사실을 알고있다.
하지만
이게 코드만 보고 명확하지 않다.
그래서 이중 해제, 누수, dangling pointer가 생긴다.
C++ 가이드라인에서 소유권이 필요하면 스마트 포인터, 소유권 자체가 필요없다면 일반 값이나 참조, 일반 포인터가 더 적절하다고 한다.
이미 해제된 메모리 영역을 가르키는 포인터를 말함
int* p = new int(10);
delete p; // p는 아직 주소 가지고 있음
function RtrnPointer()
{
int x = 10;
return &x; // 함수가 끝나면 지역변수 사라짐
}
int* p;
function RtrnPointer()
{
int x = 10;
p = &x;w
} // x소멸
std::unique_ptr<int> p = std::make_unique<int>(10);
하나의 객체만 특정 자원을 소유하는 구조.
// copy
std::unique_ptr<int> p1 = std::make_unique<int>(10);
std::unique_ptr<int> p2 = p1; // 컴파일 에러
// move
std::unique_ptr<int> p1 = std::make_unique<int>(10);
std::unique_ptr<int> p2 = std::move(p1);
#include <memory>
std::shared_ptr<int> p1 = std::make_shared<int>(10);
std::shared_ptr<int> p2 = p1; // 공동소유
shared_ptr는 여러 포인터가 같은 객체를 공동 소유한다.
같은 객체를 소유한 여러 포인터 중 마지막 포인터가 소멸되거나 다른 대상으로 지정되면 객체가 삭제된다.
자칫 소유권이 불명확한 설계를 덮어버리는 도구가 되기 쉽다.
공유 포인터는 런타임 코스트를 수반하므로 자제하는게 좋다.
#include <memory>
std::shared_ptr<int> sp = std::make_shared<int>(10);
std::weak_ptr<int> wp = sp;
if (auto locked = wp.lock())
{ ... }
weak_ptr은 shared_ptr이 관리하는 객체를 소유하지 않고 가리키기만 한다.
역참조가 불가능하며 lock()으로 임시로 shared_ptr을 얻어서 사용해야한다.
또한 expired()로 삭제 됐는지 확인이 가능하다.
가장 대표적인 이유는 순환참조 방지이다.
struct B;
struct A
{
std::shared_ptr<B> b;
}
struct B
{
std::shared_ptr<A> a; // 서로 shared_ptr이면 해제 안됨
}
위의 구조는 서로가 서로를 소유해서 참조 카운트가 0이 안된다.
때문에 메모리 릭이 발생하는데 이렇게 설계해야할 경우 한쪽을 weak으로 끊으면 된다.