VioletaBabel

2일 : 복사 금지 클래스, 가상 소멸자 본문

기본개념/Effective C++
2일 : 복사 금지 클래스, 가상 소멸자
Beabletoet 2018. 2. 20. 17:24

6. 컴파일러가 만든 함수가 필요 없을 시, 사용을 금지하라.


단 하나만 만들고 복사해선 안 될 클래스가 있는 경우엔 어떻게 하여야 하는가. 5번에서 봤듯이 복사 생성자와 복사 대입 연산자는 저절로 만들어지는데, 이를 private 멤버로 선언 후 정의를 하지 않는 방식(그냥 private 멤버로만 선언하면 friend로 접근이 가능하다.)을 이용한다. [이는 실제 iostream 헤더에서도 사용하는 하나의 기법이라고 한다.]

1
2
3
4
5
6
class A 
{
private:
    A(const A &a);// 어차피 쓸 일이 없으니 인수 이름도 빼기도 한다.
    A &operator=(const A &a); 
};
cs

그런데 이건 복사를 하려고 할 경우 링크 시점에 문제를 발생시킨다.

그러므로 더 빠른 컴파일 시점으로 문제를 앞당기는게 좋다.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Uncopy
{
protected:
    Uncopy() {}
    ~Uncopy() {}
private:
    Uncopy(const Uncopy &);
    Uncopy &operator=(const Uncopy &);
};
class A :private Uncopy
{
 
};
cs

이런 식으로 복사를 막아주는 클래스를 먼저 만든 후, 상속을 받으면 더 깔끔하게 해결할 수 있다.



================================


7. 다형성을 가진 기본 클래스의 소멸자는 가상 소멸자여야한다.


상속의 대상이 대는 기본 클래스의 경우에는 소멸자가 가상 소멸자인게 좋다.

만약 기본 클래스의 소멸자가 비가상 소멸자인 경우 대개 파생 클래스 부분이 소멸되지 않게 된다.

기본 클래스의 소멸자는

1
virtual ~Unit() {}
cs

같은 식으로 넣어주자!


그리고 가상 함수를 하나라도 가진 클래스는 가상 소멸자를 가져야 한다고 기억하자. 가상 함수는 상속해서 쓰는거니까, 어차피 어떤 클래스의 부모 클래스일 것이다. 단, 모든 클래스를 가상 소멸자로 두는 것도 좋지 않다.  가상 소멸자를 쓰는 것은 그 클래스에 가상 함수가 하나라도 들어 있는 경우로 한정하자.



가상 함수가 없는데도 비가상 소멸자로 문제가 생기는 경우가 있다. 대표적으로 string 클래스를 기본 클래스로 삼는 경우다. string 클래스는 가상 소멸자가 없고, STL의 모든 컨테이너 타입도 그렇다. 그러므로 이를 이용해 파생 클래스를 만드는 일은 자제하자.



=============================

8. 예외는 소멸자에서 빠져나와서는 안된다.


C++언어 자체에서 예외가 소멸자에서 나가는 것을 금하는 것은 아니지만, 코드를 짜는 입장에서는 반드시 막아야 한다.


만약 소멸자에서 예외가 발생하는 경우, 예외 발생 시 바로 프로그램을 종료(대개로 std::abort();를 사용)하거나, 예외를 삼켜버린다.


예외 발생 시 프로그램을 종료

1
2
3
4
5
6
7
8
9
10
11
12
A::~A()
{
    try
    {
        //예외가 발생한 함수 호출
    }
    catch(...)
    {
        //로그 작성
        std::abort();
    }
}
cs


그 외에 예외를 삼킬 필요가 있다면, 사용자가 반응하기 위해 소멸자가 아닌 보통의 함수에서 처리한다.



Comments