스마트 포인터

CJB_ny·2022년 12월 3일
0

C++ 정리

목록 보기
87/95
post-thumbnail
post-custom-banner

스마트 포인터

포인터를 알맞는 정책에 따라 관리하는 객체 (포인터를 매핑해서 사용)

1. shared_ptr

ref count를 두어서 누가 나를 기억을 하는지 체크를 하도록 하여

"댕글링 포인터" double free와 같은 문제들을 방지한다.

2. weak_ptr

이거 왜 사용하나?

shared_ptr은 cycle문제를 해결하지를 못한다.

만약 서로 다른 객체의 target이 각각 서로를 가르킬 경우.

먼저 ref count는

각각 make_shared로 만들어지면 1, 1이다.

그리고 _target으로 가르켰으니

서로 1씩 증가를 하게된다.

그리고

이 코드블록 {} 을 벗어나면 k2는 소멸되니까 ref count는 하나 줄어든다.

이게 끝임. k2는 메모리에서 사라지지 않는다.

왜냐하면 k1의 target이 k2를 가르키고있어서 ref count가 아직 1이라 소멸되지 않음.

그래서 강제적으로

nullptr로 밀면은 ref count가 자동으로 하나 줄어든다.

그래서 이렇게 강제적으로 끊어 주어야하는 문제가 발생한다.

shared_ptr로 "순환 구조"가 발생하면은 메모리가 영영 해제되지 않는다.

순환 구조가 일어날 수 있는 부분

Knight 클래스의 shared_ptr< Knight > _target이부분이 순환 구조가 발생하는 부분인데 이부분을

weak_ptr로 바꿔주면은 된다.

weak_ptr 등장

weak_ptr등장하면은 메모리 block을 당장 삭제를 하지는 않고 살려둔다.

weak_ptr로 해당 메모리가 날라갔는지 않날라갔는지 확인하는 용도로 사용할 수 있다.

shared_ptr처럼 객체의 생명주기에 직접적으로 관여하는 것은 아니지만, 객체가 소멸됬는지 안됬는지 확인하는 용도로 사용을 한다.

그래서

weak_ptr<Knight> _target;

은 막바로 void Attakc() {} 안에서 처럼 바로 사용할 수 없다.

=> 아까 말한거처럼 객체가 소멸됬는지 안됬는지 확인하는 용도로 사용한다고 했기 때문에.

expried 👍

_target.expired() 가 false라는 것은 아직 메모리가 유효하다는 것이다.

이후 lock()을 사용을 하여 (shared_ptr을 반환함)

shared_ptr로 받아준다음에 사용을 해주면 된다.

이렇게 좀 귀찮지만 두단계에 걸쳐서 사용이 가능하다.

장단점 ❗

  • 장점 :

    생명 주기에서는 자유로워 짐. weak_ptr은 shared_ptr과는 다르게 객체의 소멸에는 영향을 주지 않기 때문에, 순환구조가 일어날 수 없게 한다는 장점이 있다.

  • 단점 :

    이런식으로 expried() 로 확인을 한다음에 shared_ptr로 변경후에 다시 사용해야한다는 점이다.

정리

아까 이부분에서

서로 k1, k2를 만들면은 ref count가 1씩 증가를 함.

그리고

k1->_target = k2;
k2->_target = k1;

을 해주어도 _target이 weak_ptr이기 때문에 ref count에는 영향을 주지 않는다.

이런 경우 {} 코드블록을 벗어나면 k2는 소멸되는 경우에도 보면은

코드블록을 벗어난뒤 k1->Attack을 실행하러 가보면은

_target의 expired를 확인후애 실행하지 않음.

true값이 나오기 때문에.

3. unique_ptr

유일한 스마트 포인터임

복사 같은거 안됨.

오로지 std::move() 즉, 이동밖에 안됨. ( static_cast<K&&>(uptr)) )

이동만 허용하는 포인터이다

4. 추가 ❗❗

만약

vector<shared_ptr<GameObject>> _gameObjects; 

이런식의 shared_ptr을 가지는 vector가 있고

#################################

1for (const shared_ptr<GameObject>& gameObject : _gameObjects)
{
	gameObject->Awake();
}

##################################

이렇게 순회 할 경우와

##################################

2for (shared_ptr<GameObject> gameObject : _gameObjects)
{
	gameObject->Awake();
}

#################################

이렇게 순회 할 경우는 다른데

1번의 경우에는 ref count가 증가하지 않고

2번의 경우에는 ref count가 증가한다.
 
profile
https://cjbworld.tistory.com/ <- 이사중
post-custom-banner

0개의 댓글