티스토리 뷰
예외는 프로그램 실행 도중에 발생하는 예외적인 상황이다.
예외상황을 처리하지 않았을 떄의 결과
예외상황
-나이를 입력하라고 했는데, 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로 간다
'프로그래밍 > 윤성우의 열혈 C++' 카테고리의 다른 글
윤성우의 열혈 C++ 프로그래밍 리뷰 (1) | 2022.03.18 |
---|---|
Chapter 16 C++ 형 변환 연산자와 맺는 글 (0) | 2022.03.18 |
14 템플릿(Template) 2 (0) | 2022.03.17 |
Chapter 13 템플릿(Template) 1 (0) | 2022.03.15 |
Chapter 12 String 클래스의 디자인 (0) | 2022.03.15 |
- Total
- Today
- Yesterday
- 파이썬
- 사회심리학
- 열혈프로그래밍
- 데이터분석
- Python
- K-MOOC
- 보세사
- 코딩테스트
- 류근관
- c++
- 인지부조화
- 통계
- 정보처리기사
- 통계학
- 여인권
- C/C++
- 백준
- 티스토리챌린지
- 일본어
- 윤성우
- 강화학습
- 심리학
- 인프런
- 오블완
- C
- 일본어문법무작정따라하기
- stl
- 일문따
- 회계
- 뇌와행동의기초
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |