개요
https://product.kyobobook.co.kr/detail/S000001962302
Effective C++ | 스콧 마이어스 - 교보문고
Effective C++ | [Effective C++]은 C++ 프로그래밍과 설계 기술을 향상시켜 주는 55가지 명쾌한 테크닉을 모은 책이다.
product.kyobobook.co.kr
이번 장에서는 간단한 자원 관리의 원칙에 대해 설명합니다.
C++을 조금 공부하신 분이라면 모두 알고있는 사항이라 간단하게 점검하는 느낌으로 보시면 되겠습니다.
먼저 본격적으로 들어가기 전에 이번 장에서는 C++에서 사용하는 smart pointer에 대해 언급하기 때문에 간단한 개념만 짚어보겠습니다.
auto_ptr: RAII를 위한 스마트 포인터입니다. 스코프를 벗어나면 소멸자에서 주소에대한 delete를 해줍니다. 다만 복사가 가능해 사용자가 착각하는 일이 잦았기 때문에 현재는 사용하지 않습니다.
shared_ptr: 하나의 주소를 참조하는 곳에 대해 reference count를 셉니다. 이로 인해 한 곳에서 참조를 하지 않게 되더라도 delete되지 않아 객체의 생명을 보장합니다. ref cnt가 0이되면 그 때 삭제합니다.
weak_ptr: shared_ptr과 다르게 weak_ptr은 사용할 때만 잠시 shared_ptr로 승격시켜 사용하는 방식입니다. 따라서 수명을 보장할 수는 없고, 소유 없이 해당 객체가 안전하게 존재하는지 확인용으로 사용합니다.
unique_ptr: auto_ptr을 개선한 방식입니다. lvalue복사는 =delete로 막고 rvalue이동만 허용하는 방식으로서 사용됩니다.
Item13: 객체를 사용해 자원을 관리하라.
RAII(Resource Acquisition is Initialization)라는 패턴을 대부분 알고 계실겁니다.
RAII는 객체의 생성자에서 객체에 필요한 자원을 획득하고, 소멸자에서 반환하는 패턴입니다.
이를 통해 객체 본인이 소유한 자원을 외부에서 별도로 해제하는 것이 아니라, 자연스럽게 소멸자가 호출되며 해제되게 됩니다.
따라서 사용하는 쪽에서 실수할 확률이 적어집니다.
스마트 포인터는 기본적으로 이러한 RAII를 사용해 관리하는 포인터의 자원해제를 도와줍니다.
Item14: 자원 관리 클래스에서 복사 동작을 신중하게 고려하라.
자원 관리 클래스(RAII를 지원하는)에서 복사는 무슨 의미일까요?
복사의 경우 진짜로 모든 자원을 새로 만들어 복사하는 deep copy와 주소값만 가져오는 shallow copy가 있는데 RAII에서는 copy 시 주의하지 않으면 문제가 생길 수 있습니다.
RAII 클래스는 소멸자에서 가지고 있는 자원을 해제하는데 shallow copy시에는 이중 해제가 발생할 수 있습니다.
class B
{
public:
B()
{
cout << "B Ctor" << '\n';
}
~B()
{
cout << "B Dtor" << '\n';
}
int a = 0, b = 0;
};
class A
{
public:
A()
{
b = new B;
}
~A()
{
delete b;
}
public:
B* b;
};
int main() {
{
A a1;
A a2 = a1;
}
}
매우매우 간단한 예제를 만들어 보았습니다.
A는 B를 has a관계로 소유하는 RAII 클래스입니다.
A a1;
00EC14E0 6A 04 push 4
00EC14E2 8D 4D F8 lea ecx,[ebp-8]
00EC14E5 E8 46 00 00 00 call A::__autoclassinit2 (0EC1530h)
00EC14EA 8D 4D F8 lea ecx,[ebp-8]
00EC14ED E8 EE FE FF FF call A::A (0EC13E0h)
A a2 = a1;
00EC14F2 6A 04 push 4
00EC14F4 8D 4D F4 lea ecx,[ebp-0Ch]
00EC14F7 E8 34 00 00 00 call A::__autoclassinit2 (0EC1530h)
00EC14FC 8B 45 F8 mov eax,dword ptr [ebp-8]
00EC14FF 89 45 F4 mov dword ptr [ebp-0Ch],eax
복사 과정을 보면 위와 같은데 b포인터 값을 그대로 가져오기 때문에

소멸자가 두번 호출되고, double free로 인해 오류가 발생합니다.
따라서 RAII 클래스에 대해서는 아래와 같은 방식으로 복사를 고려해볼 수 있습니다.
1. 복사를 금지한다. + 이동만 허락한다.
복사자체는 금지하지만 소유권 이전은 허용하는 방식입니다.
기본적으로 unique_ptr이 이러한 방식을 사용합니다.
move 등을 통해 rvalue를 사용하고 실제 rvalue 대입을 구현하는 것입니다.
2. reference counting을 통해 실제 삭제를 미룬다.
이것은 shared_ptr과 비슷한 맥락에서 사용되는 방식입니다.
해당 자원을 사용하던 모든 곳에서 반환하면 자연스럽게 해제되겠죠
3. 관리하는 자원을 deep copy떠서 복사
이것은 특수한 경우에만 사용될 것입니다. 정말로 완전하게 동일한 자원을 복사하더라도 이후에는 다른 객체가 되기 때문에 관리 자체는 별도로 이루어집니다.
Item15: 자원 관리 클래스에서 원시 자원(raw resource)에 대한 접근을 제공하라.
RAII 클래스를 제공한다면 관리하는 자원을 직접 접근할 수 있도록 해야합니다.
이상적으로는 RAII클래스를 통해서 접근하면 좋지만 설계상 그러기 어렵기 때문에 편의를 위해 통로를 제공합니다.
변환 생성자나 변환 연산자를 통해 암시적 변환을 제공할 수도 있고,
별도의 메서드를 통해 명시적 변환을 제공할 수도 있겠습니다.
개인적으로는 안전하게 명시적 변환을 하는게 좋은 느낌이네요
Item16: new와 delete를 사용할 때 동일한 형태를 사용하라 .
https://basaeng.tistory.com/39
malloc과 new, free와 delete
개요malloc과 new, free와 delete는 힙 영역에 메모리를 동적 할당하는 함수이다.힙 메모리는 스택과 다르게, 프로그래머가 직접 할당하며, 해제하지 않으면 계속해서 사용할 수 있다. c에서는 malloc, fr
basaeng.tistory.com
다른 포스팅에서도 많이 다뤄보았기에 넘어가겠습니다.
단순히 짝을 맞춰야 한다는 것이 아니라 짝을 맞추지 않으면 왜 어떤 문제가 생기는지 아는 것이 중요하겠습니다.
Item17: new로 생성한 객체를 스마트 포인터에 저장할 때 독립된 문장에서 처리하라.
이것은 어쩌면 당연한 말입니다.
함수의 인자로서 new 같은 함수를 그대로 사용하면 다른 인자에서 exception이 발생했을 때 일관적이지 않은 처리가 발생할 수 있습니다.
memory leak이 발생할 수 있다는 것인데, 애초에 스마트 포인터 생성을 인자에서 하는 것은 본능적으로 꺼려지네요
'C, C++ > Effective C++' 카테고리의 다른 글
| [Effective C++] 5장 구현 (0) | 2026.02.23 |
|---|---|
| [Effective C++] 4장 설계 및 선언 (0) | 2026.02.19 |
| [Effective C++] 2장 C++의 규칙 따르자 (0) | 2026.02.06 |
| [Effective C++] 1장 C++의 규칙 따르자 (0) | 2026.02.04 |
| 7장 템플릿과 제네릭 프로그래밍 (0) | 2025.04.02 |