C++ 문법 정리 - 4 Smart Pointer, Castings
문법 정리
스마트 포인터
스마트 포인터란 자신이 소멸될 때 소멸자에서 자신이 가지고 있는 객체의 자원도 해제해주는 포인터 Wrapper 클래스라고 볼 수 있다.
unique_ptr
, shared_ptr
, weak_ptr
이 존재하며 c++11에 등장한다.
unique_ptr
특정 객체에 유일한 소유권을 부여하는 객체를 unique_ptr
이라고 한다.
이는 double free
에러를 방지한다.
std::unique_ptr<A>
처럼 사용할 수 있다.
auto a = make_unique<A>(5);
shared_ptr
다른 shared_ptr
과 동일한 객체를 공유할 수 있는 포인터이다.
use_count
로 현재 참조 개수를 알 수 있다.
void solve() {
auto a = make_shared<A>(5);
{
shared_ptr<A> b = a;
cout << a.use_count(); // 2
}
cout << a.use_count(); // 1
}
이러한 shared_ptr
들의 참조에 대한 메타데이터들은 처음으로 만들어지는 shared_ptr
가 control block을 만들어 그것에 대해 모두 참조를 하는 방식으로 데이터를 공유한다.
std::make_shared
로 생성하는 것이 동적 할당이 쓸데없이 더 되는 것을 방지할 수 있다.
std::make_unique
나 std::make_shared
는 객체 자체를 받지않고 객체의 생성자의 인자를 그대로 Perfect forwarding(by Move Semantics)하는 방식으로 받는데, 이는 동적 할당을 방지하고 성능 최적화가 되게 한다.
shared_ptr
사용시 주의점
Control block이 중복되어서 만들어지지 않게 유의해야 한다.
shared_ptr
에 주소값을 받는 생성자를 전달한다면 Control Block이 한 객체에 대해 여러개가 만들어져서 double free는 따놓은 당상이다.
따라서 웬만하면 대입 연산자와 make_shared
만을 사용해서 만드는것이 바람직하다.
weak_ptr
shared_ptr
을 약하게 참조하는 스마트 포인터이다. unique_ptr
은 참조할 수 없다.
이는 순환참조 방지용 스마트 포인터이고 weak_ptr
는 weak_ptr
나 shared_ptr
의 대입연산자나 함수의 인자로 받는것이 정형적이다.
weak_ptr
은 객체에 접근할 수 없고 lock
으로 먼저 shared_ptr
객체를 얻어온 후에 접근할 수 있다.
단, shared_ptr
로 참조하고 있던 객체가 소멸되지 않은 상태에서만 객체를 담은 shared_ptr
객체가 나오며 그렇지 않으면 사용하면 안된다.
이는 다음과 같은 코드로 사용될 수 있다.
void solve() {
std::weak_ptr<int> weak;
{
auto ptr = std::make_shared<int>(10);
weak = ptr;
}
if (std::shared_ptr<int> v = weak.lock()) {
cout << *v;
} else {
cout << "no";
}
}
no
가 호출되는 것을 볼 수 있다.
c++ Castings
static_cast
: 컴파일 타임에 타입 변환을 하고 C에서 대괄호 캐스팅과 비슷하지만 좀 더 강력한 컴파일 에러를 지원한다.dynamic_cast
: 런타임에 캐스팅을 검사하고 보통 다운캐스팅에 쓰인다.- 캐스팅에 실패한다면 포인터라면
nullptr
을 반환한다.
- 캐스팅에 실패한다면 포인터라면
const_cast
:const
를 타입에서 제거한다.reinterpret_cast
가장 위험하고 강력한 캐스팅으로, 전혀 상관없는 타입도 변환할 수 있지만 사용에 주의를 요한다.
Smart Pointer Castings
static_pointer_cast
:static_cast
의 스마트 포인터 버전dynamic_pointer_cast
:dynamic_cast
의 스마트 포인터 버전const_pointer_cast
:const_cast
의 스마트 포인터 버전
Comments