반응형
기존에 작성된 코드나 라이브러리에서 제공하는 클래스를 상속해서 사용할 때 주의 할 점이 있다. 바로 가상소멸자의 유무이다.
이번에 공부를 하면서 알게된 사실은 클래스를 만들 때 소멸자를 가상으로 만들지 않은 것은 그 클래스를 기본(Base)클래스로 사용하지 말라는 뜻을 내포한다는 것이다.
대표적인 예로 string타입, STL의 컨테이너 타입이 있다.
일단 기본클래스에 가상 소멸자로 선언되어 있지 않으면 어떤 문제가 생기는지 생각해볼 필요가 있다.
다형성을 통해 기본클래스의 포인터로 파생클래스를 제어하는 경우 파생클래스의 소멸자가 호출되지 않는 문제가 발생한다.
(virtual이 아니기 때문에 가상 함수 테이블이 생성되지 않아서)
아래의 코드는 메모리릭이 발생하는 코드이다.
[문제 코드]
class Base{public:Base(){cout<<"Base()"<<endl;}~Base() {cout<<"~Base()"<<endl;}};class Derived:public Base{public:Derived(){name = new char[10];//memory leakcout<<"Derived"<<endl;}~Derived() {delete name;cout<<"~Derived and Delete name"<<endl;}private:char* name;};int main(void){Base * p = new Derived();delete p;return 0;}
실행 결과
Base() Derived ~Base() |
결론적으로 기본클래스의 포인터로 파생클래스의 객체를 가리키는 경우 delete시 항상 메모리 누수가 발생할 수 있다.
따라서 어떤 클래스를 기본클래스로 사용하는 입장에서는 그 클래스의 소멸자가 가상으로 선언되어 있는지 확인할 필요가 있고 가상함수가 아닌 경우 원래 개발자의 의도를 생각해볼 필요가 있다. 또한 Base 클래스를 만드는 입장이라면 그 클래스의 상속을 허용한다면 반드시 소멸자를 가상함수로 만들어 주어야 한다.
[수정 된 코드]
class Base {public:Base(){cout<<"Base()"<<endl;}virtual ~Base() {cout<<"~Base()"<<endl;}};class Derived : public Base {public:Derived() {this->name = new char[10];cout<<"Derived"<<endl;}virtual ~Derived() {delete name;cout<<"~Derived and Delete name"<<endl;}private:char* name;};실행 결과
Base()
Derived
~Derived and Delete name
~Base()
ps . 소멸자는 순수 가상함수로 선언할 수 없다.
반응형
'C and C++' 카테고리의 다른 글
[C++] RAII스타일로 동작하는 lock_guard (0) | 2018.06.25 |
---|---|
[C++] 자원관리 Smart Pointer (shared_ptr) (0) | 2018.06.17 |
[C++] 기본으로 만들어지는 생성자,복사 생성자, 소멸자, 대입 연산자와 이를 금지하는 방법 (0) | 2018.05.26 |
[C++] 객체를 초기화 할때는 생성자 초기화 리스트를Initialize List) 사용하기 (0) | 2018.05.13 |
[C++] #define은 지양하자 (0) | 2018.05.06 |