Effective/Effective C++
[EC++] 5. C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자
seeyoun
2024. 11. 13. 22:01
내가 직접 만들지 않으면 컴파일러가 자동으로 만들어주는 것들
컴파일러는 경우에 따라 클래스에 대해 다음 함수들을 암시적으로 정의한다.
- 생성자
- 복사 생성자
- 복사 대입 연산자
- 소멸자
즉, 우리가 다음과 같이 선언했다면
class Empty {};
이렇게 쓴 것과 똑같다는 것이다.
class Empty
{
public:
Empty(){...} // 기본 생성자
Empty(const Empty &rhs){...} // 복사 생성자
~Empty(){...} // 소멸자
Empty& operator=(const Empty &rhs){...} // 복사 대입 연산자
};
이들은 기본적으로 public, inline으로 선언된다.
기본 클래스의 소멸자가 비가상 소멸자라면
- 파생 클래스의 소멸자도 비가상 소멸자로 만들어진다.
기본 클래스의 소멸자가 가상 소멸자라면
- 파생 클래스의 소멸자도 가상 소멸자로 만들어진다.
참조자 멤버가 있는 클래스의 복사 생성자 및 복사 대입 연산자
- 참조자 멤버가 있는 클래스는 복사 대입 연산자 사용이 어렵거나 의미가 없는 경우가 많으므로, 복사 대입 연산자를 delete하여 사용하지 않도록 하는 것이 일반적이다.
class MyClass {
public:
int& ref; // 참조 멤버
// 생성자로 참조 멤버 초기화
MyClass(int& r) : ref(r) {}
// 복사 대입 연산자를 삭제하여 사용하지 못하게 함
MyClass& operator=(const MyClass&) = delete;
};
- 또는 private 멤버로 선언하여 외부로부터의 호출을 차단할 수 있다.
- 선언만 해놓고 정의는 안하는 것이 좋다. 후에 실수로 호출하려 했더라도 링크 시점에 에러를 확인할 수 있기 때문이다.
결론
- 컴파일러가 몰래 만든 함수들로 인해 예상치 못한 오류가 발생할 수 있다는 점을 기억하자.
- 가상 소멸자가 생성되어야 하는데, 비가상 소멸자가 생성될 수 있다.
- 몰래 만들어진 복사 생성자로 인해서 예상치 못한 동작을 할 수 있다.