class Wiget {...};
Wiget w;
...
w = w;
위와 같은 소스 코드는 자기 대입이 이루어지고 있는 것을 쉽게 확인할 수 있네요.
그러나 반복문에서 이루어지는 객체의 자기 대입은 언제 놓칠 수도 있기 때문에
일치성 검사, 복사 대입 후 삭제, 복사 후 맞바꾸기 방법을 활용할 수 있습니다.
class Bitmap { ... };
class Widget
{
public:
...
private:
// 힙에 할당하기 위한 멤버
Bitmap* m_pBitmap;
public:
// 안전하지 않은 operator = 연산자
Widget& operator = (const Widget& rhs)
{
// 기존에 할당되어 있는 것을 지운다.
delete m_pBitmap;
m_pBitmap = new Bitmap(*rhs.m_pBitmap);
return *this;
}
};
위와 같은 operator = 자기 대입 연산자 오버로딩에서 rhs 인자로
메모리에서 제거 된 rhs.m_pBitmap가 들어오면 문제가 발생할 수 있습니다.
먼저 전통적인 방법인 함수의 첫머리에 쓰는 일치성 검사를 살펴보겠습니다.
일치성 검사
// 여전히 안전하지 않은 operator = 연산자
Widget& operator = (const Widget& rhs)
{
// 자기대입을 시도할 때 그대로 리턴한다.
if (this == &rhs) return *this;
// 기존에 할당되어 있는 것을 지운다.
delete m_pBitmap;
m_pBitmap = new Bitmap(*rhs.m_pBitmap);
return *this;
}
먼저 객체가 동일한지 검사합니다. 동일하지 않다면 복사 생성을 진행합니다.
그러나 Bitmap의 복사 생성자가 예외를 던지게 되면 삭제되어 있는 객체를 가리킬 수 있는 문제점이 존재합니다.
복사 대입 후 삭제
// 복사 대입 후 삭제
Widget& operator = (const Widget& rhs)
{
// 원래의 Bitmap 객체를 다른 곳에 복사해둔다.
Bitmap* pOriginBitmap = m_pBitmap;
// 새로운 사본을 생성하고 가리킨다.
m_pBitmap = new Bitmap(*rhs.m_pBitmap);
// ... 예외를 대처한다 ... //
// 원래의 Bitmap 객체를 제거한다.
delete pOriginBitmap;
return *this;
}
미리 사본을 들고 있기 때문에 복사 생성자 예외로 던져진 delete된 문제를 해결할 수 있게 되었습니다.
더 나아가 복사 후 맞바꾸기는 일치성 검사의 수고를 덜어줄 수 있습니다.
복사 후 맞바꾸기
class Bitmap { ... };
class Widget
{
...
// *this의 데이터와 rhs의 데이터를 바꾼다.
void swap(Widget& rhs);
...
// 복사 후 맞바꾸기
Widget& operator = (const Widget& rhs)
{
// rhs의 데이터에 대한 사본을 생성
Widget temp(rhs);
// *this의 데이터를 사본의 데이터와 교환
swap(rhs);
// ... 예외를 대처한다 ... //
return *this;
}
};
'Effective C++ 정리' 카테고리의 다른 글
12. 객체의 모든 부분을 빠짐없이 복사하기 (0) | 2020.01.05 |
---|---|
10. 대입 연산자는 *this의 참조자를 리턴한다 (0) | 2020.01.04 |
09. 생성자, 소멸자에서 가상 함수를 호출하지 않는다. (0) | 2020.01.04 |
08. 소멸자와 예외 처리 (0) | 2020.01.03 |
07. 다형성을 가진 기본 클래스 소멸자는 반드시 가상 소멸자로 선언하자 (0) | 2019.12.29 |