자기대입(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. 두개 이상의 객체가 함수로 넘어와 사용되면 이역시도, 자기대입을 고려하여 구현하자.
'책 정리 > Effective C++ 3rd' 카테고리의 다른 글
항목 13. 자원 관리에는 객체가 그만! (0) | 2019.12.19 |
---|---|
항목 12. 객체의 모든 부분을 빠짐없이 복사하자 (0) | 2019.12.18 |
항목 10. 대입 연산자는 *this의 참조자를 반환하게 하자 (0) | 2019.12.18 |
항목 9. 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자 (0) | 2019.12.17 |
항목 8. 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 (0) | 2019.12.17 |
댓글