• 카테고리

    질문 & 답변
  • 세부 분야

    게임 프로그래밍

  • 해결 여부

    미해결

안녕하세요! virtual 소멸자에 대해서 질문드려요!

21.02.16 20:27 작성 조회수 226

1

안녕하세요. 좋은 강의 항상 감사드립니다. 
덕분에 C# 부터 시작해서 C++까지 즐겁게 배우고 있는 중입니다. :)

다름이 아니라 질문드리고 싶은건 상위 클래스 소멸자에 virtual을 붙이지 않았을 때 메모리 Leak이 발생하는 지 테스트를 진행했는데 crtdbg를 사용해서 메모리 누수 체크를 해보니 누수된 메모리가 나오지 않았습니다.
그래서 성능 프로파일러에서 힙 프로파일링 옵션을 켠 뒤에 두 상황에 대해서 아래의 사진과 같이 비교를 해봤을 때 동일한 결과가 나왔습니다. 
이 상황에서 메모리 누수가 발생하지 않는 것인지
못찾아내고 있는 것인지 궁금합니다!

#include <iostream>
#include <iomanip>
#include <crtdbg.h>

#if _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#define malloc_d(s) _malloc_dbg(s, _NORMAL_BLOCK,__FILE__,__LINE__)
#endif

using namespace std;

class Item
{
public:
	Item()
	{
		cout << "Item()" << endl;
	}

	Item(const Item& item)
	{
		cout << "Item(const Item& item)" << endl;
	}

	Item(int itemType)
	{
		cout << "Item(int itemType)" << endl;
		_itemType = itemType;
	}

	// 상위 개념에는 virtual을 붙여야 함
	~Item()
	{
		cout << "~Item()" << endl;
	}

public:
	int _itemType = 0;
	int _itemDbId = 0;

	char _dummy[4096] = {}; // 이런 저런 정보들로 인해 비대해진 데이터라 가정
};

enum ItemType
{
	IT_WEAPON = 1,
	IT_ARMOR = 2,
};

class Weapon : public Item
{
public:
	Weapon() : Item(IT_WEAPON)
	{
		cout << "Weapon()" << endl;
		_attack = rand() % 1000;

	}

	~Weapon()
	{
		cout << "~Weapon()" << endl;

	}

public:
	int _attack = 0;
};

class Armor : public Item
{
public:
	Armor() : Item(IT_ARMOR)
	{
		cout << "Armor()" << endl;
	}

	~Armor()
	{
		cout << "~Armor()" << endl;
	}

public:
	int _defence = 0;
};

int main()
{
        // 1번 스냅샷
	Item* inventory[20] = {};

	srand(time(nullptr));

	for (int i = 0; i < 20; i++)
	{
		int randValue = rand() % 2; // 0~1

		switch (randValue)
		{
		case 0:
			inventory[i] = new Weapon();
			break;
		case 1:
			inventory[i] = new Armor();
			break;
		}
	}


	for (int i = 0; i < 20; i++)
	{
		Item* item = inventory[i];
		// 포인터 사용할 때는 항상 null 체크 필수
		if (item == nullptr)
			continue;

		if (item->_itemType == IT_WEAPON)
		{
			Weapon* weapon = (Weapon*)item;
			cout << "Weapon Damage : " << weapon->_attack << endl;
		}
	}

        // 2번 스냅샷
	for (int i = 0; i < 20; i++)
	{
		Item* item = inventory[i];
		if (item == nullptr)
			continue;

		delete item;
	}
        // crt 메모리 체크 : 메모리 Leak이 발생할 시 출력창에 표기 됨
	_CrtDumpMemoryLeaks();

        // 3번 스냅샷
	return 0;  
}
  1. virtual을 사용한 경우
  2. virtual을 사용하지 않은 경우

답변 2

·

답변을 작성해보세요.

1

igbtkd님의 프로필

igbtkd

질문자

2021.02.16

아! 제가 여쭙고 싶었던 것은 Item의 크기와 Weapon의 크기가 다를 때 delete item을 했을 때 Weapon 내부의 데이터(int와 같은 고정크기 데이터 포함)를 모두 지울 수 있는 지의 여부였습니다.  확인해보니 Weapon 생성 당시에 크기를 미리 메모리에 저장해두어서 소멸자 호출 여부와 관계없이 데이터를 지우는 것을 보았습니다! :) virtual 소멸자는 이러한 용도가 아니라 각각 자식 요소의 동적 할당에 대한 힙 제거 용이었네요! 감사합니다! 

1

위의 예제에서는 Item 소멸자에서
딱히 뭔가를 정리하고 있지는 않다보니,
설령 Item 소멸자가 호출되지 않더라도 다른 부분이 없습니다.

테스트를 위해선 Item 소멸자에서 '유의미한' 정리를 해주면 되는데요.
가령 char _dummy[4096]과 같은 고정크기 배열 대신 char* _dummy;
로 만들고 Item 생성자에서 = new char[4096]로 동적 할당을,
소멸자에서 delete[] _dummy로 삭제하는 코드 넣고
다시 테스트를 해보면 Leak을 확인할 수 있을겁니다.

rlagusdn0086님의 프로필

rlagusdn0086

2022.08.01

안녕하세요 강사님 위와 같은 코드 각 Armor와 Weapon 클래스 소멸자에 virtual 함수가 없는데요 저럴 경우에도 메모리 누설이 일어나지 않는다고 하셨는데요, 그러면 굳이 virtual 을 안쓰고 저 코드 그대로 써도 메모리 누설이 발생하지 않으면 그대로 써도 되는 거아닌가? 라는 의문점이 들었습니다.