본문 바로가기
책 정리/Effective C++ 3rd

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

by ocean20 2019. 12. 18.

자기대입(Self Assignment)이란, 어떤 객체가 자기 자신에 대해 대입연산자를 적용하는 것을 뜻한다.

자기대입 발생이유? - 중복참조(Aliasing) 가능하기때문에.

따라서 같은 클래스의 객체를 다룰때는 중복참조를 고려하여 설계해야한다.

 

1. 예외, 자기대입에 문제가 있는 예시

class Bitmap{ … }; // 동적으로 할당될 Bitmap

class Widget {
...
private:
  Bitmap *pb; // 힙에 할당된 객체를 가리키는 포인터
};

//불안정한 '=' 연산자 구현코드
Widget& Widget::operator=(const Widget& rhs)
{
  delete pb;
  pb = new Bitmap(*rhs.pb);
  return *this;
}

만약 rhs *this 같은 객체를 가리키고 있다면, delete pb 수행시 rhs의 데이터가 삭제될 것이다. -> 재앙

 

2. rhs *this의 일치성검사 통해 자기대입 문제를 해결하는 예시

Widget& Widget::operator=(const Widget& rhs)
{
  if(this == &rhs) return *this; //자기대입인지 검사
  delete pb;
  pb = new Bitmap(*rhs.pb);
  return *this;
}

*그럼에도 불구하고 코드는 예외에 노출되어 있다

pb delete new Bitmap에서 예외가 발생한다면..?

pb 삭제된 Bitmap 객체를 가리킨채 둥둥 떠다닐 것이다.

 

3. 코드 순서변경을 통한 자기대입, 예외문제를 해결하는 예시

Widget& Widget::operator=(const Widget& rhs)
{
  Bitmap *pOrg = pb;
  pb = new Bitmap(*rhs.pb);
  delete pOrg;

  return *this;
}

*new Bitmap에서 예외가 발생하더라도 pb 변경되지 않는다. (예외에 안전)

*this rhs 가리키는 같은 타입의 객체인 pb 대입한다. (자기대입에 안전)

*, 문장 순서를 세심하게 바꾸므로 예외에 안전한(동시에 자기대입에도 안전한)코드가 만들어진다.

cf) 일치성비교를 바로 코드에도 구현하고 싶지만, 분기발생과 같은 비용이 들기때문에… 속력이 저하될 있다.

 

이외에도 '복사 맞바꾸기(copy and swap)' 기법이 있지만 항목 29. 에서 상세히 다뤄볼 예정이다.

 

이것만은 잊지 말자!

  1. operator = 구현할때, 자기대입을 고려하여 구현하자.

    (1) 일치검사비교

    (2) 세심한 코드 순서 조정

    (3) copy and swap 기법 활용

 

  2. 두개 이상의 객체가 함수로 넘어와 사용되면 이역시도, 자기대입을 고려하여 구현하자.

댓글