[Effective C++] 항목 14 : 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자

수민이슈·2023년 3월 20일
0

Effective C++

목록 보기
14/30
post-thumbnail

스콧 마이어스의 Effective C++을 읽고 개인 공부 목적으로 요약 작성한 글입니다!

💡 RAII 객체의 복사는 그 객체가 관리하는 자원의 복사문제를 안고 가기 때문에,
그 자원을 어떻게 복사하느냐에 따라 RAII 객체의 복사 동작이 결정된다!
💡 RAII 클래스에 구현하는 일반적인 복사 동작은 복사를 금지하거나, 참조 카운팅을 해주는 것이다.
이외에도 진짜 복사하기, 소유권 이전하기 등도 가능하긴 하다..!


🖊️ 힙에 생기지 않는 자원 관리

직접 자원 관리 클래스를 만들자

void lock(Mutex* pm);
void unlock(Mutex* pm);

class Lock {
public:
	explicit Lock(Mutex* pm) : mutexPtr(pm) { lock(mutexPtr); }
    ~Lock() { unlock(mutexPtr); }
    
private:
	Mutex* mutexPtr;
};

이런 큐텍스를 조작하는 관리 클래스를 만든다고 치면,
RAII 법칙을 따라 생성 시 자원을 획득하고, 소멸시 그 자원을 해제하도록 만들어야 한다.

이러한 객체를 RAII 객체라고 하자


🖊️ RAII 객체의 복사 동작

Mutex m;

Lock m11(&m);
Lock m12(m11);

이 상황은 어떻게 해야 하냐?

복사를 금지하자

RAII 객체를 복사 금지로 만든다.
그냥 아예 안된다고 막는다.
스레드 동기화 객체와 같은 상황에서는 사본이 만들어지면 안되니까!

class Lock : private UnCopyable {
public:
	...
}

무느알?
UnCopyable과 같이,, (항목 6 참고)
복사 생성자, 복사 대입 연산자를 private으로 선언해놓고 정의하지 않은 기본 클래스로부터 상속받자

관리하고 있는 자원에 대해 참조 카운팅을 수행하자

shared_ptr처럼!!

해당 자원을 참조하는 객체의 개수에 대한 카운트를 증가시키는 방식으로 복사를 수해하도록 두자.
근데 shared_ptr가 이렇게 동작하니까
클래스의 Mutex* mutexPtrstd::tr1::shared_ptr<Mutex> mutexPtr로 만들고 싶자나

근데
shared_ptr는 참조 카운트가 0이 될 때 자신이 가리키고 있는 대상을 삭제해버린다
우리는 unlock만 하면 되는데 굳이 얘는 삭제를 시킨다는 거지

근데!!

shard_ptr는 삭제자 지정을 허용한다

뭔소리냐면
일단
삭제자 : shared_ptr가 유지하는 참조 카운트가 0이 되었을 때 호출되는 함수 (혹은 함수 객체)

그니까 참조 카운트가 0이 되었을 때 하고 싶은 동작 지정이 가능하다는거다!!
(auto_ptr는 이런 기능 없음. 그냥 포인터 바로 삭제해버림)
개꿀

class Lock {
public:
	explicit Lock(Mutex* pm) : mutexPtr(pm, unlock) { lock(mutexPtr.get()); }
    
private:
	std::tr1::shared_ptr<Mutex> mutexPtr;
};

이렇게 되니까 굳이 소멸자를 선언해줄 필요가 없다.

클래스의 소멸자는 비정적 데이터 멤버의 소멸자를 자동으로 호출해준다.
mutexPtr는 비정적 데이터 멤버니까
mutexPtr의 소멸자는 참조 카운트가 0이 되면 unlock을 자동으로 호춣래줄거다.

진짜로 복사하자

진짜로 걍 복사해버린다
깊은 복사 (deep copy)로 조져버린다

하고 싶다는 대로 복사 해주고, 자원을 다 썼으면 각각의 사본을 다 해제해주기만 하자.

깊은 복사 (deep copy)

예를 들어서 표준 string 타입이라 치면,
문자열을 구성하는 원소들을 힙 메모리에 저장해놓고,
이 메모리에 대한 포인터를 데이터 멤버로 갖는다.

-> 결국 힙 메모리를 포인터로 물고 있는 형태!!

이 객체를 복사하면,
포인터와 그 포인터가 가리키는 새로운 힙 메모리를 가지게 된다.

이게 깊은 복사다!

관리하고 있는 자원의 소유권을 이전하자

auto_ptr 처럼!!

특정 자원에 대해 그 자원을 실제로 참조하는 RAII 객체는 딱 하나만 존재하도록 만드는 거다
RAII 객체가 복사될 때 그 자원의 소유권을 사본으로 그냥 옮겨준다.


😊 느낀점

자원 관리 클래스,,
재작년쯤 스마트포인터의 복사 문제를 실제로 겪었던 적이 있다
사실 unique_ptr에 대한 이해를 전혀 못하고 그냥 갖다가 썼다가 난리를 친 경험이지만..
그래서 좀 열심히 읽었다
생각해보고, 또 생각해보고!
컴파일러가 만들어주는 소멸자를 자동으로 호출되게 이런 부분은 진짜 ,,
난 바보고 이 사람들은 천재구나 싶어
ㅠㅠ

0개의 댓글