자기대입(self assignment) |
문제는 무엇인가? |
같은 타입으로 만들어진 객체 여러 개를 참조자 혹은 포인터로 물어 놓고 동작하는 코드를 작성할 때는 같은 객체가 사용될 가능성을 고려하는 것이 일반적으로 바람직한 자세라고 할 수 있겠습니다. 사실, 같은 클래스 계통에서 만들어진 객체라 해도 굳이 똑같은 타입으로 선언할 필요까지는 없습니다. 파생 클래스 타입의 객체를 참조 하거나 가리키는 용도로 기본 클래스의 참조자나 포인터를 사용하면 되니까 말이죠. 그럼 대입연산자에서는 무엇을 조심해야 할까요? 아래와 같이 동적 할당된 비트맵을 가리키는 원시 포인터를 데이터 멤버로 갖는 클래스가 있다고 한번 해봅시다.
물론 이것에 대한 대책은 있습니다.
전부는 아니지만, operator=을 예외에 안전하게 구현하면 대개 자기대입에도 안전한 코드가 나오게 되어 있습니다. 즉, 예외 안전성에만 집중하면 자기대입 문제에 대해서는 그렇게 걱정을 안해도 된다는 의미죠. 여기에서는 pb를 무조건 삭제 하지 말고 이 포인터가 가리키는 객체를 복사한 직후에 삭제하면 예외에 대한 문제를 해결 할 수 있습니다. 아래와 같이 말이죠.
위의 코드는 new Bitmap 부분에서 예외가 발생하더라도 pb는 변경되지 않는 상태가 유지되기 때문에 예외에 안전합니다. 또한 원본 비트맵을 복사해 놓고, 복사해 놓은 사본을 포인터가 가리키게 만든 후, 원복을 삭제하는 순서로 실행되기 때문에 일치성 검사 없이도 자기대입 현상을 완벽히 처리 하고 있죠. 물론 이 방법 말고도 다른 복사 후 맞바꾸기(Copy and Swap) 이라는 방법도 있습니다.
복사 후 맞바꾸기(Copy and Swap) |
- 첫째, 클래스의 복사 대입 연산자는 인자를 값으로 취하도록 선언하는 것이 가능하다.
- 둘째, 값에 의한 전달을 수행하면 전달된 대상의 사본이 생긴다
* 두 개 이상의 객체에 대해 동작하는 함수가 있다면, 이 함수에 넘겨지는 객체들이 사실 같은 객체인 경우에 정확하게 동작하는지 확인하자.
'Effective C++' 카테고리의 다른 글
항목 13. 자원 관리에는 객체가 그만! (shared_ptr, auto_ptr) (2) | 2010.10.08 |
---|---|
항목 12. 객체의 모든 부분을 빠짐없이 복사하자. (0) | 2010.10.07 |
항목 10. 대입 연산자는 *this의 참조자를 반환하게 하자. (0) | 2010.10.06 |
항목 9. 객체 생성 및 소멸 과정중에는 절대 가상 함수를 호출하지 말자!!! (0) | 2010.10.06 |
항목 8. 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 (0) | 2010.10.05 |