프로그래밍/C\C++

[Effective C++ 정리 #6] 복사 금지! 컴파일러가 몰래 만든 함수 차단 방법

허구의 2025. 6. 16. 07:24
728x90

이 글은 『Effective C++』를 읽고 개인적으로 공부한 내용을 정리한 기록입니다.

저는 컴퓨터공학을 전공하지 않았으며, 프로그래밍을 공부하는 과정에서의 이해와 생각을 정리하기 위해 글을 작성하고 있습니다.

따라서 내용 중 일부에 오류나 부정확한 설명이 있을 수 있으며, 피드백은 언제든지 환영합니다. 확인 후 수정하도록 하겠습니다.

전문적인 해설이 아닌 개인적 시선에서의 정리임을 참고하고 읽어주시면 감사하겠습니다.

[Effective C++ 정리 #6] 복사를 막고 싶다면 컴파일러가 만든 함수부터 차단하라

C++ 컴파일러는 우리가 명시하지 않아도 복사 생성자복사 대입 연산자를 자동으로 만들어줍니다. 하지만 어떤 클래스는 복사가 허용되어선 안 됩니다. 예를 들어, '집 한 채'를 복사해서 또 다른 동일한 집을 만든다는 건 말이 안 되죠.

이번 아이템에서는 '복사가 의미 없는 클래스'에서 복사를 방지하는 안전하고 명확한 방법을 공부합니다.


복사를 허용하면 안 되는 경우

예를 들어, 부동산 중개 시스템에 아래와 같은 클래스가 있다고 가정해 봅시다.

class HomeForSale { ... };

 

모든 매물은 고유합니다. 따라서 HomeForSale 객체는 복사될 수 없도록 막아야 합니다.

HomeForSale h1;
HomeForSale h2;
HomeForSale h3(h1); // ❌ 복사 생성자 사용 — 막고 싶음
h1 = h2;            // ❌ 복사 대입 연산자 사용 — 막고 싶음

 

문제는 우리가 복사 생성자나 대입 연산자를 작성하지 않더라도, 컴파일러가 자동으로 이 함수들을 생성해버린다는 데 있습니다.


어떻게 복사를 막을 수 있을까?

복사를 막기 위한 기본 전략은 다음과 같습니다:

  • 복사 생성자와 복사 대입 연산자를 직접 선언하여 컴파일러의 자동 생성을 막는다.
  • 이들을 private으로 선언하여 외부 접근을 차단한다.
  • 정의는 하지 않는다. (링크 단계에서 에러 발생)

즉, 다음과 같이 선언만 하고 구현하지 않는 패턴을 사용합니다.

class HomeForSale {
public:
    HomeForSale();  // 생성자는 public
    ~HomeForSale(); // 소멸자도 public

private:
    HomeForSale(const HomeForSale&);             // 복사 생성자 (선언만)
    HomeForSale& operator=(const HomeForSale&);  // 복사 대입 연산자 (선언만)
};

 

이렇게 하면 컴파일러는 더 이상 자동 생성을 하지 않고, 누군가 복사를 시도할 경우 컴파일 또는 링크 오류가 발생합니다.

이 방식은 C++ 표준 라이브러리의 iostream 계열 클래스 (ios_base, basic_ios 등)에서도 널리 사용됩니다.


더 세련된 방식: Uncopyable 베이스 클래스

복사를 막기 위해 매번 private 복사 생성자와 대입 연산자를 선언하는 건 번거롭습니다. 이럴 때는 다음처럼 베이스 클래스를 활용하면 훨씬 깔끔하게 구현할 수 있습니다.

class Uncopyable {
protected:
    Uncopyable() {}
    ~Uncopyable() {}

private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
};

 

이제 Uncopyable을 상속만 하면, 그 클래스는 자동으로 복사가 금지됩니다.

class HomeForSale : private Uncopyable {
    ...
};

 

이 방식은 다음과 같은 장점이 있습니다:

  • 코드 중복이 없고 일관성 유지
  • 의도가 명확하여 유지보수성 향상
  • 링크 에러 대신 컴파일 에러 발생 가능 (더 빠른 피드백)

Boost 라이브러리에는 이와 동일한 역할을 하는 noncopyable 클래스가 존재합니다. #include <boost/noncopyable.hpp>를 통해 간단히 사용할 수 있습니다.


핵심 요약

  • 복사를 막고 싶다면, 해당 함수들을 private 선언 + 미구현으로 해결 가능하다
  • Uncopyable 같은 베이스 클래스를 활용하면 반복을 줄이고 명확성을 높일 수 있다.

감사합니다.

728x90