C++ delete 사용에 대한 유의점

정채운·2023년 11월 3일
0

Example.cpp

int main()
{
	srand(static_cast<unsigned int>(time(nullptr)));

	Archer* archer = new Archer(new Pet());
	archer->_hp = 100;
	archer->_maxHp = 100;
	archer->_attack = 20;

	Knight* knight = new Knight();	
	knight->_hp = 150;
	knight->_maxHp = 150;
	knight->_attack = 10;
	
	Arrow* arrows[10] = {};
	for (int i = 0; i < 10; i++)
	{
		// 기사를 타겟으로, 궁수의 공격력을 지닌 상태
		Arrow* arrow = new Arrow(knight, archer->_attack);
		arrows[i] = arrow;
	}

	for (int i = 0; i < 10; i++)
	{
		arrows[i]->AttackTarget();

		// 기사가 죽었으면 소멸시켜준다
		if (knight != nullptr)
		{
			if (knight->IsDead())
			{
				delete knight;
				knight = nullptr;
			}
		}	

		delete arrows[i];
		arrows[i] = nullptr;
	}
}

Arrow.cpp

Arrow::Arrow(Player* target, int damage) 
	: _target(target), _damage(damage)
{

}

Arrow::~Arrow()
{

}

void Arrow::AttackTarget()
{
	cout << "화살이 적을 피격합니다!" << endl;

	// 공격 대상이 있다면
	if (_target != nullptr)
	{
		// 데미지를 입힌다
		_target->AddHp(-_damage);
		_target->PrintInfo();
	}
}

상황 요약

  • Archer와 Knight 하나씩 만들고 10개의 Arrow을 만듬
  • Arrow의 첫번째 매개변수는 Player타입 공격대상(target)의 포인터를 받고 두번째 매개변수는 int형 damage라는걸 받는 상황
  • 반복문을 돌려 knight를 10번 공격하고 knight가 죽으면 delete로 소멸시켜주는 상황
  • Arrow.cpp에서 AddHp는 일반함수 PrintInfo는 가상함수

문제점

  1. 만약 knight가 데미지를 받고 죽게되어 delete knight 되는 순간 힙영역의 메모리들이 정리가 됨 하지만 Arrow에서 받는 target은 knight가 소멸됐다는 정보가 없음

  2. target에 담겨있는 주소를 따라가 AddHp, PrintInfo를 수행하게 됨 하지만 도착지는 이미 delete되어 아무것도 없는 상태

  3. 여기서 AddHp는 크래쉬없이 수행되지만 PrintInfo에서는 크래쉬가 발생

문제 3번의 이유

  • PrintInfo는 가상함수로 만들어져 있기 때문에 Player에서 만든 PrintInfo를 Knight에서도 오버라이딩을 해서 PrintInfo를 만들어 주었기때문에
    처음에 생성되었던(new Knight()) 원본을 기억하므로 (target에 가상함수 테이블의 주소가 저장 되어 있기 때문)
    해당 함수로 knight의 정보를 출력하게 되어 크래쉬가 일어남
    반면 AddHp는 일반함수이기 때문에 Player에 있는 AddHp가 수행됨

어떤게 더 문제일까?

  • PrintInfo는 크래쉬를 내주어서 개발자가 잘못한 부분을 크래쉬를 내어 알려주지만
    AddHp는 그냥 수행이 되기 때문에 메모리 오염이 발생함 -> 엉뚱한 메모리를 고치게 됨 -> 디버깅 하기가 되게 어려워짐

결론

  • Arrow가 처리가 된 상태에서 delete knight를 해줘야 함

0개의 댓글