//코드없는 프로그래밍 강의를 보고 정리한 내용입니다.

정의 및 특징

  • 여러개의 포인터가 하나의 오브젝트를 공유하는 포인터

    모든 스마트 포인터는 RAII를 지켜야 한다. 참조갯수가 0 이 될때
    소멸자가 자동으로 호출된다.

  • 하나의 객체를 여러개의 포인터가 가리키더라도, 문제가 되지 않는다.

  • 참조갯수를 이용해 RAII 규칙을 지킨다.
    동일한 객체를 가리킬때마다 참조 갯수가 증가한다.
    스코프 벗어나 참조갯수가 0이 될때 오브젝트의 해제가 일어난다.
  • 여러개의 포인터들이 소유권을 공유한다.


제어블록

: shared_ptr내부의 제어블록이라는 자료구조가 있는데,
참조 카운팅을 관리한다.
실제 객체를 가리키는 shared_ptr이 제어블록을 동적으로 할당한 후, shared_ptr들이 이 제어블록의 필요한 정보를 공유하게 된다.
따라서 shared_ptr은 복사 생성할때마다 제어블록의 위치만 공유한다.
객체를 참조할때마다 참조 카운팅 갯수가 증가하며,
더이상 사용되지 않는 순간, 스코프를 벗어날 경우에 참조 카운팅 개수가 감소하며, 0이 되는 순간에 shared_ptr은 해제된다.

제어블록이 필요한 이유는

이와 같은 상황에서 c는 3, b는 3, a는 2가 되는데 ,
제어블록을 통해서 이를 방지하기 위함이다.

make_shared_ptr을 사용해야 하는 이유

: shared_ptr은 공동으로 사용하기 위해서 제어블록을 동적으로 할당하게 되는데, new를 이용해 shared_ptr을 만들게 되면 동적할당을 2번이나 하는 꼴이다.

  • make_shared는 생성자의 인자들을 받아서 객체와 제어블록까지 한번에 동적할당한후에 만들어진 shared_ptr을 반환하게 된다.

주의할점 - 제어블록을 2개이상 만들어질 수 있다.

: 인자로 주소값이 전달되면 , 마치 자기가 첫번째로 소유하는 shared_ptr인 것 마냥 행동한다.
공동의 제어블록을 공유해야만 관리가 가능하지만, 서로 다른 제어블록이라면
소멸후에 문제가 발생한다.

  • 2개의 제어블록이 할당되어서 발생하는 문제이다.
    -> 주소로 전달되는 것을 지양하자.

  • 해결하는 방법이 있다.

enable_shared_from_this를 사용하자.

잘못 사용하면 memory Leak이 발생한다. - 중요

  • 억지로 만듦.

  • 클래스 내부에 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이 만들어졌다.


-> 소멸자가 호출되지 않았다.

weak_ptr

-> 멤버를 weak_ptr로 사용할 경우, 카운팅이 발생하지 않으므로 문제 없음.

profile
🔥🔥🔥

0개의 댓글