Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 3법칙(Rule of Three)이란? 복사 생성자, 대입 연산자, 소멸자 완벽 정리

C++의 3법칙(Rule of Three)이란?

3법칙(Rule of Three)은 C++ 프로그래밍에서 널리 통용되는 경험 법칙입니다. 좋은 코딩 습관을 위한 지침으로, 클래스에 다음 세 가지 중 하나라도 명시적으로 정의해야 한다면 나머지 두 가지도 함께 정의하는 것이 바람직하다는 내용입니다.

  • 복사 생성자(copy constructor)
  • 대입 연산자(assignment operator)
  • 소멸자(destructor)

왜 세 가지가 모두 필요할까?

그 이유는 간단합니다. 클래스가 위의 기능 중 하나라도 필요하다는 것은 해당 클래스가 동적으로 할당된 리소스를 관리하고 있다는 의미이기 때문입니다. 리소스를 올바르게 관리하려면 나머지 두 가지도 반드시 필요합니다.

예를 들어 대입 연산자가 필요한 상황을 생각해 보겠습니다. 객체를 복사할 때 참조(reference)로 전달되는 것이 아니라 실제 복사본을 만드는 과정에서 리소스 할당이 발생합니다. 이때 복사를 수행하려면 복사 생성자가, 사용이 끝난 리소스를 해제하려면 소멸자가 각각 필요합니다.

세 가지 요소 자세히 살펴보기

1. 복사 생성자(Copy Constructor)

컴파일러가 자동으로 제공하는 복사 생성자는 모든 멤버 변수를 하나씩 그대로 복사하는 멤버별 복사(member-wise copy) 방식으로 동작합니다. 이는 대입 연산자와 동일한 문제를 일으킬 수 있습니다. 포인터 멤버가 있다면 얕은 복사(shallow copy)로 인해 두 객체가 같은 메모리를 공유하게 되어 이중 해제(double free) 같은 심각한 오류가 발생할 수 있습니다.

2. 대입 연산자(Assignment Operator)

대입 연산자를 직접 정의하지 않으면 컴파일러가 기본 대입 연산자를 생성합니다. 기본 대입 연산 역시 멤버별 복사 방식으로, 깊은 복사(deep copy)가 아닌 얕은 복사(shallow copy)를 수행합니다. 이로 인해 메모리 누수(memory leak), 잘못된 값 대입과 같은 문제가 발생할 수 있습니다.

3. 소멸자(Destructor)

객체가 스코프(scope)를 벗어나 소멸될 때, 해당 객체가 관리하던 모든 리소스를 반드시 해제해야 합니다. 이 역할을 담당하는 것이 소멸자이며, 동적으로 할당된 메모리나 파일 핸들 등을 적절히 정리하지 않으면 리소스 누수로 이어집니다.

정리 및 확장 개념

결론적으로, 클래스가 동적 리소스를 관리한다면 복사 생성자, 대입 연산자, 소멸자 세 가지를 모두 직접 정의하는 것이 안전합니다. 참고로 현대 C++(C++11 이후)에서는 여기에 이동 생성자(move constructor)와 이동 대입 연산자(move assignment operator)를 추가한 5법칙(Rule of Five)이 권장되며, std::unique_ptr 같은 스마트 포인터를 활용해 리소스 관리를 자동화하는 0법칙(Rule of Zero)을 지향하는 것도 좋은 방법입니다.