예제 1. 매개 변수를 사용하는 생성자의 초기화 문제

#include "Knight.h"
#include <iostream>
using namespace std;

Knight::Knight() : _hp(100), _attack(10)
{

}

Knight::Knight(int hp) : _hp(hp)// 공격력이 초기화 되어있지 않음.
{

}

Knight::~Knight()
{

}

void Knight::PrintInfo()
{
	cout << "HP: " << _hp << endl;
	cout << "ATT: " << _attack << endl;
}

기본 사양이 _hp = 100, _attack = 10인 기사 둘을 만든다.

첫 기사는 기본 생성자를 이용하여 만들고, 두번째 기사는 Knight* k2 = new Knight(200); 로 hp가 지정된 기사를 만들었다.

이 때 hp가 지정되는 생성자에서 공격력이 초기화 되어있지 않으므로

Knight::Knight(int hp) : _hp(hp), _attack(10)
{ // ~~

으로 수정해준다.

 

 

예제 2. 이상한 메모리에 접근

#include <iostream>
using namespace std;
#include "Knight.h"

// [Bug Report #2]
// Bug Report #1이 잘 해결 되었는지 확인하기 위해
// 기사 10명 생성해서 정보를 출력하고자 합니다.
// 그런데 정보를 출력하다 프로그램이 뻗는 문제1가 발생하고 있습니다.
// 크래시 원인을 분석하고 알맞게 고쳐주세요!

const int KNIGHT_COUNT = 10;

int main()
{
	Knight* knights[KNIGHT_COUNT];

	for (int i = 0; i < KNIGHT_COUNT; i++)
	{
		knights[i] = new Knight();
	}

	for (int i = 0; i <= KNIGHT_COUNT; i++) // 등호로 문제 발생
	{
		knights[i]->PrintInfo();
		delete knights[i];
	}
}

위의 반복문으로 인해 knights는 총 0~9까지의 요소를 가지는 배열로 만들어진다.

이 문제는 출력과 delete를 반복하는 반복문에서 등호가 포함되어 마지막으로 생성되지 않은 knights[10]에 접근하려 하다가 발생한 문제이다. 이 때는 등호를 제거해주면 된다.

 

예제 3. 판별식을 잘못 작성

void Knight::AddHp(int value)
{
	_hp += value;
}

bool Knight::IsDead()
{
	return (_hp == 0); // 판별식 오류
}

void Knight::PrintInfo()
{
	cout << _hp << endl;
	cout << _attack << endl;
}

캐릭터의 사망을 체크하기 위해 k1을 한번에 죽일 수 있는 공격력을 가진 k2가 k1을 공격했을 때에도

k1이 죽지 않는 버그가 발생하였다.

그 이유는 k1의 체력이 음수가 되면서 불리언인 IsDead가 false를 반환했기 때문이다.

따라서 판별식을 작거나 같음으로 수정해주거나, hp가 0보다 작거나 같으면 0으로 만들어주도록 한다.

 

(1) 판별식 수정

bool Knight::IsDead()
{
	return (_hp <= 0);
}

(2) 음수 hp 보정

bool Knight::IsDead()
{
	if (_hp <= 0)
	_hp = 0;

	return (_hp == 0);
}

 

 

예제 4. 정수 오버플로우

int main()
{
	Knight* k1 = new Knight();
	k1->_hp = 100;
	k1->_attack = 10;

	const int TEST_COUNT = 100 * 10000; // 100만
	const int TEST_VALUE = 100 * 10000; // 100만

	for (int i = 0; i < TEST_COUNT; i++)
	{
		k1->AddHp(TEST_VALUE);
	}

	if (k1->IsDead())
	{
		cout << "죽었습니다!" << endl;
	}
	else
	{
		cout << "엥? 살았습니다!" << endl;
	}

	delete k1;
}

HP에 100만을 더하는 작업을 100만번 시도하였다.

이론상 int형의 가능한 정수 범위는 –2,147,483,648 ~ 2,147,483,647 이므로, 위의 코드를 100만번 반복하였을 때 기사의 HP가 -727,379,868이 된다.

따라서 hp를 int형이 아닌 __int64로 지정해준다.

class Knight
{
public:
	Knight();
	Knight(long long hp);
	~Knight();

	void PrintInfo();

	void AddHp(int value);
	bool IsDead();

public:
	long long _hp;
	int _attack;
};
// Knight.h

Knight::Knight(long long hp) : _hp(hp), _attack(10)
{

}
// Knight.cpp

아니면 _hp 변수의 최대값을 지정해 줄 수 있다.

'기초 C++ 스터디 > 예제' 카테고리의 다른 글

7-3. 디버깅 예제 #8 ~ 10  (0) 2023.06.07
7-2. 디버깅 예제 #5 ~ 7  (0) 2023.06.07
7-0. 디버깅 연습  (0) 2023.06.07
6-6. Text RPG - OOP  (0) 2023.06.02
4-14. 달팽이 문제  (0) 2023.05.23