티스토리 뷰

반응형

예외는 프로그램 실행 도중에 발생하는 예외적인 상황이다.

 

예외상황을 처리하지 않았을 떄의 결과

예외상황

-나이를 입력하라고 했는데, 0보다 작은 값이 입력되었다.

-나눗셈을 위한 두 개의 정수를 입력 받는데, 나누는 수로 0이 입력되었다.

-주민등록번호 13자리만 입력하라고 했더니, 중간에 -를 포함하여 14자리를 입력하였다.

 

정상적인 값이 주어졌을 때는 잘 되지만, 예외가 발생하면 프로그램을 종료해버린다.

-> 프로그램을 종료하지 않고, 그 예외의 처리가 일어나야한다.

 

#include <iostream>
using namespace std;

int main(void)
{
	int num1, num2;
	cout << "두 개의 숫자 입력: ";
	cin >> num1 >> num2;

	if (num2 == 0)
	{
		cout << "제수는 0이 될 수 없습니다." << endl;
		cout << "프로그램을 다시 실행하세요." << endl;
	}
	else
	{
		cout << "나눗셈의 몫: " << num1 / num2 << endl;
		cout << "나눗셈의 나머지: " << num1 % num2 << endl;
	}
	return 0;
}

예외가 발생할 경우 다시 실행하게 만든다.

 

 

15-2 C+의 예외처리 메커니즘

C++의 예외처리 메커니즘의 이해:try와 catch 그리고 throw의 이해

 

try 예외를 발견한다

catch 예외를 잡는다

throw 예외를 던진다

 

try블록

예외발생에 대한 검사의 범위를 지정할 떄 사용

try

{

 //예외발생 예상지역

}

 

catch 블록

catch(처리할 예외의 종류 명시)

{

 //예외처리 코드의 삽입

}

 

사실 try와 catch는 하나의 문장이다.

try

{

}

catch

{

}

 

throw

예외가 발생했음을 알리는 문장에 구성에 사용된다.

 

#include <iostream>
using namespace std;

int main(void)
{
	int num1, num2;
	cout << "두 개의 숫자 입력: ";
	cin >> num1 >> num2;
	
	try
	{
		if (num2 == 0)
			throw num2;
		cout << "나눗셈의 몫: "<<num1/num2 << endl;
		cout <<"나눗셈의 나머지: " <<num1%num2<< endl;
	}
	catch(int expn)
	{
		cout << "제수는  " << expn<<"이 될 수 없습니다" << endl;
		cout << "프로그램을 다시 실행하세요 " << endl;
	}
	cout << "end of main" << endl;
	return 0;
}

 

try 블록을 묶는 기준

-try 블록을 만나면 그 안에 삽입된 문장이 순서대로 실행된다.

-try 블록 내에서 예외가 발생하지 않으면, catch 블록 이후를 실행한다.

-try 블록 내에서 예외가 발생하면, 예외가 발생한 지점 이후의 나머지 try 영역은 건너띈다.

 

try는 예외가 발생할만한 영역만 묶는 것이 아니라 하나의 일 단위로 묶는다.

 

 

15-3 Stack Unwinding(스택 풀기)

#include <iostream>
using namespace std;


void Divide(int num1, int num2)
{
	if (num2 == 0)
		throw num2;
	cout << "나눗셈의 몫: " << num1 / num2 << endl;
	cout << "나눗셈의 나머지: " << num1 % num2 << endl;
}
int main(void)
{
	int num1, num2;
	cout << "두 개의 숫자 입력: ";
	cin >> num1 >> num2;
	
	try
	{
		Divide(num1, num2);
		cout << "나눗셈을 마쳤습니다" << endl;
	}
	catch(int expn)
	{
		cout << "제수는  " << expn<<"이 될 수 없습니다" << endl;
		cout << "프로그램을 다시 실행하세요 " << endl;
	}
	cout << "end of main" << endl;
	return 0;
}

 

예외가 처리되지 않으면, 예외가 발생한 함수를 호출한 영역으로 예외 데이터가 전달된다.

 

 

예외상황이 발생한 위치와 예외상황을 처리해야 하는 위치가 다른 경우

#include <iostream>
#include <cstring>
#include<cmath>
using namespace std;


int StoI(char* str)
{
	int len = strlen(str);
	int num = 0;

	for (int i = 0; i < len; i++)
	{
		if (str[i] < '0' || str[i]>'9')
			throw str[i];
		num += (int)(pow((double)10, (len - 1) - i) * (str[i] + (7 - '7')));
	}
	return num;
}

int main(void)
{
	char str1[100];
	char str2[100];

	while (1)
	{
		cout << "두 개의 숫자 입력: ";
		cin >> str1>>str2;

		try
		{
			cout << str1 << " + " << str2 << " = " << StoI(str1) + StoI(str2) << endl;
			break;
		}
		catch (char ch)
		{
			cout << "문자 " << ch << "가 입력되었습니다." << endl;
			cout << "재입력 진행합니다." << endl << endl;
		}
	}
	cout << "프로그램을 종료합니다." << endl;
	return 0;
}

 

함수 내에서 함수를 호출한 영역으로 예외 데이터를 전달하면, 해당 함수는 더 이상 실행되지 않고 종료된다.

 

 

스택풀기

#include <iostream>
#include <cstring>
#include<cmath>
using namespace std;


void SimpleFuncOne(void);
void SimpleFuncTwo(void);
void SimpleFuncThree(void);

int main(void)
{
	try
	{
		SimpleFuncOne();
	}
	catch (int expn)
	{
		cout << "예외코드: " << expn << endl;
	}
	return 0;
}
void SimpleFuncOne(void)
{
	cout << "SimpleFuncOne(void)" << endl;
	SimpleFuncTwo();
}
void SimpleFuncTwo(void)
{
	cout << "SimpleFuncTwo(void) " << endl;
	SimpleFuncThree();
}
void SimpleFuncThree(void)
{
	cout << "SimpleFuncThree(void)" << endl;
	throw - 1;
}

스택 안에

SimpleFuncThree

SimpleFuncTwo

SimpleFuncOne

main

 

이런 식으로 쌓인다. 그리고 위에서부터 스택이 쌓인 순서로 풀려나간다.

 

 

자료형이 일치하지 않아도 예외 데이터는 전달됩니다.

try

{

 if()

  trhow -1;

}

catch(char expn){ }

 

-> 캐릭터형 예외 데이터를 전달, 그러면 catch 블록으로 예외가 전달하지 않고, SimpleFunc 함수를 호출한 영역으로 예외데이터가 전달된다.

 

 

하나의 try 블록과 다수의 catch 블록

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cstring>
#include<cmath>
using namespace std;


int StoI(char* str)
{
	int len = strlen(str);
	int num = 0;

	if(len!=0 && str[0]=='0')
		throw 0;

	for (int i = 0; i < len; i++)
	{
		if (str[i] < '0' || str[i]>9)
			throw str[i];
		num += (int)(pow((double)10, (len - 1) - i) * (str[i] + (7 - '7')));
	}
	return num;
}

int main(void)
{
	char str1[100];
	char str2[100];

	while (1)
	{
		cout << "두 개의 숫자 입력: ";
		cin >> str1 >> str2;

		try
		{
			cout << str1 << " + " << str2 << " = " << StoI(str1) + StoI(str2) << endl;
			break;
		}
		catch (char ch)
		{
			cout << "문자 " << ch << "가 입력되었습니다." << endl;
			cout << "재입력이 진행됩니다." << endl << endl;

		}
		catch (int expn)
		{
			if (expn == 0)
				cout << "0으로 시작하는 숫자는 입력불가." << endl;
			else
				cout << "비정상적 입력이 이루어졌습니다." << endl;

			cout << "재입력 진행합니다." << endl << endl;
		}
	}
	cout << "프로그램 종료합니다." << endl;
	return 0;
}

 

 

전달되는 예외의 명시

 

int ThrowFunc(int num) throw (int, char)

{

 . . . .

}

int형과 char형 오류가 반환될 수 있다.

 

try

{

 ThrowFunc(20);

}

catch(int expn){ . . .}

catch(char expn){ . . . .}

 

int형이나 char형 이외에는 그냥 함수가 종료된다.

 

 

15-4 예외상황을 표현하는 예외 클래스의 설계

예외발생을 알리는데 사용하는 객체를 '예외객체'라고 한다.

 

class DepositException
{
private:
	int reqDep;//요청입금액
public:
	DepositException(int money) : reqDep(money)
	{}
	void ShowExceptionReason()
	{
		cout << "[예외 메시지: " << reqDep << "는 입금불가]" << endl;
	}

};

class WithdrawException
{
private:
	int balance;//잔고
public:
	WithdrawException(int money):balance(money)
	{}
	void ShowExceptionReason()
	{
		cout << "[예외 메시지: 잔액" << balance << ", 잔액부족]" << endl;
	}
};

class Account
{
private:
	char accNum[50];
	int balance;
public:
	Account(char* acc, int money) :balance(money)
	{
		strcpy(accNum, acc);
	}

	void Deposit(int money) throw (DepositException)
	{
		if (money < 0)
		{
			DepositException expn(money);
			throw expn;
		}
		balance += money;
	}
	void Withdraw(int money) throw(WithdrawException)
	{
		if (money > balance)
			throw WithdrawException(balance);
		balance -= money;
	}
	void ShowMyMoney()
	{
		cout << "잔고: " << balance << endl << endl;
	}
};

 

상속관계에 있는 예외 클래스

 

class AccountException

{

public:

 virtual void ShowExceptionTeason()=0; //순수가상함수

};

 

class DepositException: public AccountException

 

 

예외의 전달방식에 따른 주의 사항

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cstring>
#include<cmath>
using namespace std;


class AAA
{
public:
	void ShowYou() { cout << "AAA exception!" << endl; }
};

class BBB :public AAA
{
public:
	void ShowYou() { cout << "BBB Exception!" << endl; }
};

class CCC :public BBB
{
public:
	void ShowYou() { cout << "CCC exception!" << endl; }
};

void ExceptionGenerator(int expn)
{
	if (expn == 1)
		throw AAA();
	else if (expn == 2)
		throw BBB();
	else
		throw CCC();
}

int main(void)
{
	try
	{
		ExceptionGenerator(3);
		ExceptionGenerator(2);
		ExceptionGenerator(1);
	}
	catch (AAA& expn)
	{
		cout << "catch(AAA& expn" << endl;
		expn.ShowYou();
	}
	catch (BBB& expn)
	{
		cout << "catch(BBB& expn" << endl;
		expn.ShowYou();
	}
	catch (CCC& expn)
	{
		cout << "catch(CCC& expn" << endl;
		expn.ShowYou();
	}
	return 0;
}

이렇게 함수 호출을 하면

 

상속 탓에 AAA 예외 호출만 하고 뒤에건 호출되지 않는다.

 

이경우를 해결하려면 catch의 순서를 CCC, BBB, AAA의 순서로 해야한다.

 

 

15-5 예외처리와 관련된 또 다른 특성들

new 연산자에 의해서 발생하는 예외

#include <iostream>
#include <new>

using namespace std;

int main(void)
{
	int num = 0;

	try
	{
		while (1)
		{
			num++;
			cout << num << "번째 할당 시도" << endl;
			new int[10000][10000];
		}
	}
	catch (bad_alloc& bad)
	{
		cout << bad.what() << endl;
		cout << "더 이상 할당 불가!" << endl;
	}
	return 0;
}

 

bad_cast와 bad_alloc에 대해 16챕터에서 설명한다고 한다.

 

모든 예외를 처리하는 catch 블록

catch(...) //...은 모든 예외를 다 받아주겠다느 ㄴ선언

{

. . . .

}

무슨 예외인지 구분도 불가하고 좋지도 않다.

 

 

예외 던지기

catch블록에 전달된 예외는 다시 던져질 수 있다.

 

#include <iostream>
#include <new>

using namespace std;


void Divide(int num1, int num2)
{
	try
	{
		if (num2 == 0)
			throw 0;
		cout << "몫: " << num1 / num2 << endl;
		cout << "나머지: "<<num1 % num2 <<endl;
	}
	catch (int expn)
	{
		cout << "first catch" << endl;
		throw;
	}
}
int main(void)
{
	try
	{
		Divide(9, 2);
		Divide(4, 0);
	}
	catch(int expn)
		{
		cout << "second catch" << endl;
		}
	return 0;
}

몫 4

나머지 1

frist catch

second catch

 

처음에 실패하면 아래에 catch로 간다

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함