C++11의 5의 법칙(Rule of Five)이란?
C++에서 5의 법칙(Rule of Five)은 리소스 관리를 위해 적용되는 중요한 설계 원칙입니다. 리소스 관리가 제대로 이루어지면 클라이언트 코드는 관리 대상 객체의 수명(lifetime)을 신경 쓸 필요가 없어지며, 메모리 누수와 같은 문제를 사전에 방지할 수 있습니다.
하지만 이러한 관리에는 비용이 따릅니다. 5의 법칙은 다음 다섯 가지 함수 중 하나라도 직접 작성해야 한다면, 나머지 함수들에 대한 정책도 반드시 함께 마련해야 한다는 규칙입니다.
예를 들어 객체 Foo가 있고, 이를 관리하는 FooManager 클래스를 구현한다고 가정해 봅시다. 이 경우 일반적으로 아래 다섯 가지 함수를 모두 고려해야 합니다.
1. 소멸자(Destructor)
관리자 객체가 범위(scope)를 벗어날 때, 자신이 관리하던 모든 리소스를 해제해야 합니다.
2. 대입 연산자(Assignment Operator)
직접 정의하지 않으면 컴파일러가 기본 대입 연산자를 생성합니다. 기본 대입 연산은 멤버 단위 복사(member-wise copy), 즉 얕은 복사(shallow copy)만 수행하며 깊은 복사(deep copy)는 하지 않습니다. 이로 인해 메모리 누수나 잘못된 대입과 같은 문제가 발생할 수 있습니다.
3. 복사 생성자(Copy Constructor)
컴파일러가 제공하는 기본 복사 생성자 역시 FooManager의 모든 멤버를 멤버 단위로 복사합니다. 따라서 대입 연산자와 동일한 문제가 발생할 수 있습니다.
4. 이동 생성자(Move Constructor)
객체 복사는 임시 객체를 생성하고, 복사한 뒤, 소멸하는 과정을 거치기 때문에 비용이 상당히 클 수 있습니다. C++11에서는 이를 개선하기 위해 r-value 참조(r-value reference) 개념이 도입되었습니다. r-value 참조는 r-value에 명시적으로 바인딩될 수 있으며, 여기서 r-value란 이름 없는 객체, 즉 임시 객체를 의미합니다. 이 r-value 참조를 생성자에서 활용하면 전달받은 임시 객체에 대한 참조를 효율적으로 만들 수 있습니다.
5. 이동 대입 연산자(Move Assignment Operator)
리소스를 한 번에 하나만 유지하는 것이 유용한 경우가 있습니다. 이럴 때 리소스의 소유권(ownership)을 한 관리자에서 다른 관리자로 이전할 수 있으며, 이러한 상황에서 이동 대입 연산자를 제공하면 됩니다.
마무리
5의 법칙은 C++에서 안전하고 효율적인 리소스 관리를 위한 필수 지침입니다. 다섯 가지 특수 함수를 하나의 일관된 정책으로 관리함으로써 메모리 누수, 이중 해제, 불필요한 복사 비용 등의 문제를 예방할 수 있습니다.
더 자세히 학습하고 싶다면 Feabhas에서 제공하는 PDF 자료(Rule of the Big Five)를 참고하는 것도 좋은 방법입니다.