본문 바로가기

카테고리 없음

클래스 동적할당

class A
{
public:
	virtual void Output()
	{
		cout << "AA" << endl;
	}

	A() {}
	~A() {} // ... ㄱ
    virtual ~A() {} // ... ㄴ
};

class B : public A
{
public:
	virtual void Output()
	{
		cout << "BB" << endl;
	}

	B() {}
	~B() {} // ... ㄷ
    virtual ~B() override {} // ... ㄹ
};

int main()
{
	A* aPtr1 = new A; // ... ㅁ
	delete aPtr1; // ... ㅂ

	A* aPtr2 = new B; // ... ㅅ
	delete aPtr2; // ... ㅇ

	return 0;
}

위의 코드의 ㅅ를 메모리 구조로 그림을 그려보면 다음과 같다.

위 코드의 ㅁ의 경우 ㅂ를 통해 자연스럽게 메모리가 해제된다.

하지만  ㅅ의 경우 포인터의 자로형과 실제 대입된 클래스가 다르기 때문에 문제가 발생할 수 있다.

ㅇ을 통해서 heap 영역에 동적할당 받는 B부분은 해제가 될 테지만 소멸자의 문제가 생길 수 있다.

소멸자는 자식클래스가 먼저 호출되어서 볼일이 끝나면 부모 소멸자가 호출되는 순서이다.

이때 aPtr 은 A* 자료형이기에 제일 먼저 A클래스의 소멸자를 호출한다. 따라서 B의 소멸자가 호출되지 않는것이다.

만약 코딩의 B 클래스 부분에 어떠한 변수에 대한 해제 부분이 있었다거나 하면 결과적으로 메모리 누수가 발생하는 셈이다. 따라서 가장 최상의 클래스의 소멸자인 ~A를 가상함수로 정의 해야 한다. 소멸자가 가상함수이면 메모리 해제 시에 소멸자를 호출하기 위해 v table 을 살펴볼 것이고 그렇게 되면 모든 소멸자를 호출할 수 있게 되기 때문이다. 따라서 최상위 클래스는 무조건 ㄱ이 아닌 ㄴ과 같이 소멸자를 선언해야 한다. 또한 상속받는 파생 클래스들은 ㄹ 이 옳으나 ㄷ과 같이 선언해도 문제는 없다.