스토리텔링 개발자

[Effective C++] 11. operator= 자기 대입 문제 본문

개발/Effective C++

[Effective C++] 11. operator= 자기 대입 문제

김디트 2024. 5. 30. 11:07
728x90

항목 11. operator = 에서는 자기 대입에 대한 처리가 빠지지 않도록 하자

 

 

 

자기 대입
  • 자기 자신에 대해 대입 연산자를 적용하는 것.

 

 

 

자기 대입에 대한 처리가 필요한 이유
  • 중복 참조 때문에 자기 대입이 생길 수 있다.
    • int i = 1;
      int& ci1 = i;
      int& ci2 = i;
      ci1 = ci2; // 중복참조로 인한 자기대입
  • 같은 타입 객체 여럿을 참조자 / 포인터로 사용하는 코드를 작성할 때는 같은 객체가 사용될 가능성을 고려해야 한다.

 

 

 

자기 대입 문제의 예시
class Bitmap { ... };

class Widget
{
private:
    Bitmap* pb;
};

Widget& Widget::operator=(const Widget& rhs)
{
    delete pb;
    pb = new Bitmap(*rhs.pb); // &rhs와 this가 같을 경우 rhs.pb 역시 삭제되어 버린다!
    
    return *this;
}

 

  • 매개변수로 넘어온 객체가 자기 자신일 경우(자기 대입일 경우) pb가 삭제된 상태로 남아버리는 문제가 있다.

 

 

 

처리법
  1. 일치성 검사
    • Widget& Widget::operator=(const Widget& rhs)
      {
          if(this == &rhs) return *this; // 객체가 같은지 검사
      
          delete pb;
          pb = new Bitmap(*rhs.pb);
          
          return *this;
      }
    • 예외에 안전하지 못할 수 있다.
      • new Bitmap 표현식에서 예외가 터지면 Widget 객체의 pb는 결국 삭제된 Bitmap을 가리키는 포인터로 남게 된다.
  2. 더 나은 방법 : 문장 순서 조정
    • Widget& Widget::operator=(const Widget& rhs)
      {
          Bitmap* pOrig = pb;
          pb = new Bitmap(*rhs.pb);
          delete pOrig; // 원래의 pb를 기억해뒀다가 삭제
          
          return &this;
      }
    • 이제 new Bitmap에서 예외가 발생해도 pb는 기존 상태를 유지하므로 예외에 안전하다.
  3. 또 다른 방법 : 복사 후 맞바꾸기(copy and swap)
    • class Widget{
          void swap(Widget& rhs); // 스왑 기능
      };
      
      Widget& Widget::operator=(const Widget& rhs)
      {
          Widget temp(rhs);
          swap(temp); // rhs의 사본과 *this의 데이터를 스왑
          return *this;
      }
    • 이는 C++의 아래 두 가지 특징을 활용해서 조금 다르게 구현할 수 있다.
      1. 클래스의 복사 대입 연산자는 인자를 참조가 아니라 값으로 취하도록 선언할 수 있다.
      2. 값에 의한 전달을 수행하면 전달된 대상의 사본이 생긴다.
    • Widget& Widget::operator=(widget rhs) 
      { 
          swap(rhs); 
          return *this; 
      }
    • 가독성이 떨어지지만, 객체 복사 코드가 함수 본문에서 매개변수의 생성자로 옮겨졌으므로 컴파일러가 더 효율적인 코드를 생성할 여지가 있다.

 

 

728x90
Comments