작성
·
362
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;
}
답변 2
1
아! 제가 여쭙고 싶었던 것은 Item의 크기와 Weapon의 크기가 다를 때 delete item을 했을 때 Weapon 내부의 데이터(int와 같은 고정크기 데이터 포함)를 모두 지울 수 있는 지의 여부였습니다. 확인해보니 Weapon 생성 당시에 크기를 미리 메모리에 저장해두어서 소멸자 호출 여부와 관계없이 데이터를 지우는 것을 보았습니다! :) virtual 소멸자는 이러한 용도가 아니라 각각 자식 요소의 동적 할당에 대한 힙 제거 용이었네요! 감사합니다!
1
위의 예제에서는 Item 소멸자에서
딱히 뭔가를 정리하고 있지는 않다보니,
설령 Item 소멸자가 호출되지 않더라도 다른 부분이 없습니다.
테스트를 위해선 Item 소멸자에서 '유의미한' 정리를 해주면 되는데요.
가령 char _dummy[4096]과 같은 고정크기 배열 대신 char* _dummy;
로 만들고 Item 생성자에서 = new char[4096]로 동적 할당을,
소멸자에서 delete[] _dummy로 삭제하는 코드 넣고
다시 테스트를 해보면 Leak을 확인할 수 있을겁니다.
안녕하세요 강사님 위와 같은 코드 각 Armor와 Weapon 클래스 소멸자에 virtual 함수가 없는데요 저럴 경우에도 메모리 누설이 일어나지 않는다고 하셨는데요, 그러면 굳이 virtual 을 안쓰고 저 코드 그대로 써도 메모리 누설이 발생하지 않으면 그대로 써도 되는 거아닌가? 라는 의문점이 들었습니다.