내용
자기대입(self assignment) : 어떤 객체가 자기 자신에 대해 대입 연산자를 적용 하는 것을 말한다.
a[i] = a[j]; 또는 *px = *py; 는 자기대입의 가능성을 가지고 있는 문장이다. 어뜻 보기에 명확하지 않은 이러한 자기대입이 생기는 이유는 여러 곳에서 하나의 객체를 참조하는 상태, 즉 중복참조(aliasing)라고 불리는 것 때문이다.
그렇기 때문에, 같은 타입으로 만들어진 객체 여러개를 참조자 혹은 포인터로 물어 놓고 동작하는 코드를 작성할 떄는 같은 객체가 사용 될 가능성을 고려 하는것이 일반적으로 바람직한 자세이다.
해결법
- operator=의 첫머리에서 일치성 검사(identity test)를 통해 자기대입을 점검한다.
자기대입의 경우 많이 일어나는 것이 아니기 때문에 모든 객체에 대해서 비교하는 것은 효율이 낮다.
- 문장의 순서를 적절히 조정한다.
- 복사 후 맞바꾸기(copy and swap) 기법을 사용한다.
class CEx { ... }; CTest& CTest::operator=(const CTest& rhs) { if ( this == &rhs) return *this; // 객체가 같은지, 즉 자기대입인지 검사한다. // 자기대입이면 아무것도 안한다. delete pMember; pMember = new CEx(*rhs.pMember); return *this; }
class CEx { ... }; CTest& CTest::operator=(const CTest& rhs) { CEx *pOrig = pMember; // 원래의 pMember를 어딘가에 기억해 둔다. pMember = new CEx(*rhs.pMember);// 다음, pMember가 *pMember의 사본을 가르키게 만든다. delete pOrig; // 원래의 pMember를 삭제한다. return *this; }
class CTest { ... void swap(CTest& rhs); // *this의 데이터 및 rhs의 데이터를 맞바꾼다. ... }; CTest& CTest::operator=(const CTest& rhs) { CTest temp(rhs); // rhs의 데이터에 대한 사본을 하나 만든다. swap(temp); // *this의 데이터를 그 사본의 것과 맞바꾼다. return *this; }
이것만은 잊지 말자!
- operator=을 구현할 때, 어떤 객체가 그 자신에 대입되는 경우를 제대로 처리하도록 만들자. 원본 객체와 복사대상 객체의 주소를 비교해도 되고, 문장의 순서를 적절히 조정할 수도 있으며, 복사 후 맞바꾸기 기법을 써도 된다.
- 두 개 이상의 객체에 대해 동작하는 함수가 있다면, 이 함수에 넘겨지는 객체들이 사실 같은 객체인 경우 정확하게 동작하는지 확인해 보자.
관련링크
http://ikpil.tistory.com/413
http://jangyeol.springnote.com/pages/348598.xhtml
http://evax.springnote.com/pages/871438
http://ilu8318.egloos.com/1705010
http://ikpil.tistory.com/299
'Programming > Effective C++ 3판' 카테고리의 다른 글
항목 12. 객체의 모든 부분을 빠짐없이 복사하자. (0) | 2009.02.17 |
---|---|
항목 11. operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자 (0) | 2009.02.17 |
항목 10. 대입 연산자는 *this 참조자를 반환하게 하자 (0) | 2009.02.15 |
항목 9. 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자. (0) | 2009.02.15 |
항목 8. 예외가 소멸자를 떠나지 못하도록 붙들여 놓자. (0) | 2008.07.10 |
항목 7. 다형성을가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자. (0) | 2008.07.01 |
항목 6. 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자. (0) | 2008.06.27 |
항목 5. C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자 (0) | 2008.06.27 |
항목 4. 객체를 사용하기 전에 반드시 그 객체를 초기화하자. (0) | 2008.06.10 |
항목 3. 낌새만 보이면 const를 들이대 보자! (0) | 2008.06.10 |
항목 2. #define을 쓰려거든 const, enum, inline을 떠올리자. (0) | 2008.05.29 |