반응형
항목 5 : C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자.
이유 : 컴파일러는 클래스의 생성자, 소멸자 등을 자동으로 만들어 내는데, 만약 멤버 변수로 포인터 등이 존재할 경우. 완전한 깊은 복사를 수행하지 않게 된다.
해결 : 클래스 선언시 생성자, 복사 생성자, 복사 대입 생성자, 소멸자, 이동 생성자( c++ 11) 이동 복사 생성자 (c++ 11) 등을 명시적으로 선언해두자.
항목 6 : 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자
이유 : 구조적으로 복사되면 안되는 경우 ( 단 하나만 존재하는 클래스 등 ) 클래스를 사용하는 쪽에서 자동으로 생성된 복사 생성자를 이용해 버릴 수 있다.
해결 : 자동으로 생성되는 함수들을 private 로 선언하거나, = delete 키워드를 선언해 줌으로써 명시적으로 사용을 금지시키자.
항목 7 : 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자
이유 : 파생 클래스를 기본 클래스 타입의 변수에 대입하고 소멸을 시킬 때, 기본 클래스의 소멸자를 호출하기 때문이다.
해결 : 소멸자를 가상 소멸자로 선언함으로써, 다형성이 적용되게 하면 해결된다.
항목 8 : 예외가 소멸자를 떠나지 못하도록 붙들어 놓자
이유 : 에외가 소멸자를 떠난다는 의미는, 소멸자에서 예외상황이 발생하고 소멸자를 빠져나가지 않도록 하자는 것이다. STL컨테이너에 10 개의 클래스 인스턴스를 보관하다가 벡터를 할당 해제하며 2번째 클래스 인스턴스 소멸자에서 에러가 난 경우, 또 3번째에서 또 난 경우 예외가 2번이나 발생하게 되고, c++에서는 정의되지 않은 동작을 야기한다고 한다.
해결 : 소멸자 내에서 예외를 삼켜 버리거나 (무시하거나), 프로그램을 바로 끝내도록 하자. 또는 예외가 일어날 가능성이 있는 코드를 사용자가 호출하도록 함수로 빼 버리자.
항목 9 : 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자
이유 : 기본 클래스와 파생 클래스가 존재하고, 파생 클래스를 생성하면 먼저 기본 클래스의 생성자가 호출되고, 그 다음 파생 클래스의 생성자가 호출된다. 이 과정에서 기본 클래스 생성자 내부의 가상 함수는 기본 클래스의 가상 함수를 호출하게 된다. 그렇기 때문에 프로그래머의 예상과 다른 동작을 할 가능성이 있다.
* 중요한 점 : 파생 클래스가 생성 되면서 기본 클래스의 생성자를 호출하는 동안에는 그 객체는 '기본 클래스' 이다.
해결 : 굳이 생성자에서 호출해야 한다면. 비 가상 함수로 선언하고, 파생 클래스에서 생성자를 호출 할 때 기본 클래스의 생성자를 호출하게 만들자.
예 :
BaseClass {
BaseClass ( baseParameters )
{
doSomething( baseParameters )
}
};
};
DerivedClass {
public:
DerivedClass ( parameters )
: BaseClass ( makeForBase( parameters ) )
{
}
};
위 상황은 '파생 클래스' 에서 '기본 클래스' 로 정보를 넘겨 주고 싶을 경우에 저렇게 하라는 소리이다.
항목 10 : 대입 연산자는 *this의 참조자를 반환하게 하자
cout << "1" << "2" << "3" << endl;
value1 = value2 = value3 = 4;
위와 같이 c++ 에서는 대입 연산자를 사슬처럼 엮어서 사용 할 수 있도록 설계되어 있다.
이런 관례를 지키는 편이 좋기 때문에 대입 연산자의 리턴값을 *this 를 리턴하라고 한다.
항목 11 : operator= 에서는 자기대입에 대한 처리가 빠지지 않도록 하자
이유 : 서로 다른 객체를 받아서 처리하는 함수가 있을 때, 같은 객체가 들어오는 경우가 있다. A 가 B 라는 인스턴스를 받아서 A의 원소를 제거하고 B를 대입하는 경우에 A == B 관계가 성립할 경우, B의 원소를 제거하고 B를 제거하는 이상한 동작을 하게 된다. 이런 경우를 피하기 위해 예외처리를 항상 해 두자
해결 : 언제나 자기 자신이 파라미터로 들어올 경우에 대한 대비를 하자. ( 비교를 하거나, 대입 후 제거를 하거나)
항목 12 : 객체의 모든 부분을 빠짐없이 복사하자
이유 : 프로그래머가 객체를 복사하는 함수를 생성할 때, 실수로 기본 클래스의 값 등을 복사하지 않고 넘어가는 경우가 생길 수 있다
해결 : 복사 생성자를 호출한다면 기본 클래스의 복사 생성자도 같이 호출을 하고, 해당 멤버의 모든 값을 복사하도록 구현하자
잘못 이해한 부분에 대한 태클, 지적 환영합니다.
반응형
'개발자의 길 > Effective C++' 카테고리의 다른 글
[Effective C++] Chapter 6 상속, 그리고 객체 지향 설계 (작성중) (0) | 2020.03.07 |
---|---|
[Effective C++] Chapter 5 구현 (0) | 2020.03.07 |
[Effective C++] Chapter 4 설계 및 선언 (0) | 2020.02.29 |
[Effective C++] Chapter 3 자원 관리 (0) | 2020.02.29 |