//코드없는 프로그래밍 강의를 보고 정리한 내용입니다.
여러개의 포인터가 하나의 오브젝트를 공유하는 포인터
모든 스마트 포인터는 RAII를 지켜야 한다. 참조갯수가 0 이 될때
소멸자가 자동으로 호출된다.
하나의 객체를 여러개의 포인터가 가리키더라도, 문제가 되지 않는다.
: shared_ptr내부의 제어블록이라는 자료구조가 있는데,
참조 카운팅을 관리한다.
실제 객체를 가리키는 shared_ptr이 제어블록을 동적으로 할당한 후, shared_ptr들이 이 제어블록의 필요한 정보를 공유하게 된다.
따라서 shared_ptr은 복사 생성할때마다 제어블록의 위치만 공유한다.
객체를 참조할때마다 참조 카운팅 갯수가 증가하며,
더이상 사용되지 않는 순간, 스코프를 벗어날 경우에 참조 카운팅 개수가 감소하며, 0이 되는 순간에 shared_ptr은 해제된다.
제어블록이 필요한 이유는
이와 같은 상황에서 c는 3, b는 3, a는 2가 되는데 ,
제어블록을 통해서 이를 방지하기 위함이다.
: shared_ptr은 공동으로 사용하기 위해서 제어블록을 동적으로 할당하게 되는데, new를 이용해 shared_ptr을 만들게 되면 동적할당을 2번이나 하는 꼴이다.
: 인자로 주소값이 전달되면 , 마치 자기가 첫번째로 소유하는 shared_ptr인 것 마냥 행동한다.
공동의 제어블록을 공유해야만 관리가 가능하지만, 서로 다른 제어블록이라면
소멸후에 문제가 발생한다.
2개의 제어블록이 할당되어서 발생하는 문제이다.
-> 주소로 전달되는 것을 지양하자.
해결하는 방법이 있다.
억지로 만듦.
클래스 내부에 shared_ptr을 만들고 멤버에 저장하면 memoryLeak 이 발생한다.
catptr객체가 할당되면서 참조 카운팅이 하나 증가해서 1이 된다.
객체내의 스마트 포인터로 지신을 참조하면 , 참조카운팅이 하나 증가해서
참조 카운팅이 2가 된다.
스코프를 벗어나면서 catptr의 참조 카운팅이 1 감소하면서 참조카운팅이 1이 된다. 하지만, 클래스 내부의 스마트포인터 멤버가 해제되는 것이 아니므로,
참조 카운팅은 계속해서 1로 유지가 되므로, 메모리 릭이 발생한다.
-> 메모리 릭이 발생한다.
#include <iostream>
using namespace std;
class Cat
{
public :
Cat()
{
cout << "Cat constructor " << endl;
}
~Cat()
{
cout << "Cat Destructor " << endl;
}
shared_ptr<Cat> mFriend;
};
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
shared_ptr<Cat> pkitty = make_shared<Cat>();
shared_ptr<Cat> pNabi = make_shared<Cat>();
pkitty->mFriend = pNabi;
pNabi->mFriend = pkitty;
}
-> 소멸자가 호출되지 않았다.
-> 멤버를 weak_ptr로 사용할 경우, 카운팅이 발생하지 않으므로 문제 없음.