광고


[C++11] "default" and "delete" keyword TR1 / C++11 / C++14




들어가기에 앞서, 다음 링크는 default / delete에 대한 C++ 표준 문서이다.


C++ 클래스를 사용 하다보면, 컴파일러가 은근슬쩍 만들어내는 함수가 4가지가 있다.
  • 기본 생성자
  • 복사 생성자
  • 대입 연산자
  • 소멸자
이것들이 보통의 경우 별로 신경 쓸 일이 없는데, 다음과 같은 상황에선 손을 좀 써 줘야 한다.


1. 기본 생성자 요구 (default)

  1. class NonCopyable
  2. {
  3. private:
  4.     NonCopyable(const NonCopyable&);
  5. };
  6.  
  7. int main()
  8. {
  9.     // Compile error : C2512: 'NonCopyable' : 사용할 수 있는 적절한 기본 생성자가 없습니다.
  10.     NonCopyable nc;
  11. }

    기본 생성자는 기본 생성자가 아닌, 어떠한 생성자라도 존재할 경우 자동으로 생성되지 않는다.
    (이것이 복사 생성자가 되었던, 인자를 가지는 다른 형태의 생성자이든 말이다).

    따라서, 기본 생성자 형으로 객체를 생성하면, 사용할 수 있는 적절한 기본 생성자가 없다며 컴파일 에러가 발생한다.
    이 경우, 아래와 같이 기본 생성자를 직접 선언/정의해 주어야 컴파일 에러가 발생하지 않는다.

    1. class NonCopyable
    2. {
    3. public:
    4.     NonCopyable() {}
    5.  
    6. private:
    7.     NonCopyable(const NonCopyable&);
    8. };
    9.  
    10. int main()
    11. {
    12.     NonCopyable nc;
    13. }

    이 경우 C++11에서는 아래와 같이 default 생성자를 선언만으로 해결할 수 있다.

    1. class NonCopyable
    2. {
    3. public:
    4.     NonCopyable() = default;
    5.  
    6. private:
    7.     NonCopyable(const NonCopyable&);
    8. };
    9.  
    10. int main()
    11. {
    12.     NonCopyable nc;
    13. }

      위 예제에서는 NonCopyable() 생성자의 default 생성을 명시적으로 요구하였으므로, 기본 생성자가 생성된다.


      2. 복사, 대입 금지 클래스 (delete)

      특정 클래스에 대해선 복사도 대입도 막고 싶은 경우 기존 C++ 0x 까진 아래와 같이 작성하였다.

      1. class NonCopyable
      2. {
      3. public:
      4.     NonCopyable() {}
      5.     ~NonCopyable() {}
      6.  
      7. private:
      8.     NonCopyable(const NonCopyable&);
      9.     NonCopyable& operator = (const NonCopyable&);
      10. };

      위 방식은 우선 복사 생성자와 대입 연산자를 private으로 두어 외부에서 접근 에러가 발생하게 하는 방식이고,

      만약, 위 코드에서 복사 생성자와 대입 연산자의 접근 지정자를 public으로 두었다면,
      선언만 하고 정의를 하지 않아 링크 에러가 나게 하는 식으로 사용을 금지시키는 방식이었다.

      이를 C++11의 delete를 명시적으로 붙여주면, 이들에 대한 사용이 확실히 금지 된다.

      1. class NonCopyable
      2. {
      3. public:
      4.     NonCopyable() {}
      5.     ~NonCopyable() {}
      6.  
      7.     // 명시적으로 복사 생성자 / 대입 연산자가 disable 처리 되었음
      8.     NonCopyable(const NonCopyable&) = delete;
      9.     NonCopyable& operator = (const NonCopyable&) = delete;
      10. };

      음 여기까지만 봤을 땐, 뭐 기존에 비해 크게 이득이 뭔가 싶겠지만,
      delete의 경우 조금 더 요긴하게 사용할 수 있다.

      delete 키워드는 아무 함수에나 사용할 수 있기 때문에, 
      멤버 함수의 파라미터에 대해 암시적인 형변환이 일어나는 것을 사전에 방지할 수 있다.

      1. // int 타입에 대해선 받지 않겠음.
      2. struct NoInt
      3. {
      4.     void f(double i);
      5.     void f(int) = delete;
      6. };
      7.  
      8. // f의 인자로 double 형을 제외하고는 완전히 금지하겠다.
      9. // 즉, 컴파일러가 암시적으로 형 변환하는 것까지 완벽 차단.
      10. struct OnlyDouble
      11. {
      12.     void f(double d);
      13.     template<class T> void f(T) = delete;
      14. };

      지금까지 default / delete 키워드에 대해 알아 보았지만, 아쉽게도 vs2013부터만 지원된다.


        덧글

        • 모카노 2015/06/02 20:24 # 삭제 답글

          C++11의 default에 대해서 많이 궁금했었는데 잘 알고 갑니다.
        • 요원009 2015/07/28 14:18 # 답글

          아하! 어디다 쓰나 고민이 많았는데... 감사합니다.
        • dewlit 2016/12/02 15:52 # 삭제 답글

          잘 보고갑니다. 감사합ㄴ다.
        댓글 입력 영역