예제 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 |