도순씨의 코딩일지
C++ :: 예외처리(try, catch, throw) 본문
🌼 C++의 예외처리 : try, catch, throw
💡 try : 예외를 발견한다
💡 catch : 예외를 잡는다
💡 throw : 예외를 던진다
위 설명을 더 자세하게 살펴보도록 합시다.
try 블록은 예외발생에 대한 검사의 범위를 지정합니다. try 블록에서 예외가 발생하면 catch 부분으로 넘어가 예외를 처리합니다. 키워드 throw는 예외가 발생했음을 알립니다. throw에 의해서 던져진 '예외 데이터'는 try 블록에 의해서 감지가 되고 catch 블록에 의해서 처리됩니다.
예제를 한 번 살펴봅시다.
⭐️ HandlingExceptionTryCatch.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#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;
}
|
cs |
⭐️ HandlingExceptionTryCatch.cpp 실행결과 (예외 X)
1
2
3
4
|
두 개의 숫자 입력: 9 2
나눗셈의 몫: 4
나눗셈의 나머지: 1
end of main
|
cs |
⭐️ HandlingExceptionTryCatch.cpp 실행결과 (예외 O)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#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;
}
|
cs |
num2가 0이기 때문에 예외 처리에 의해서 catch 부분에 의하여 예외가 처리되었습니다. try 블록을 묶는 기준은 예외가 발생할 문장을 모두 묶는 것입니다.
🌼 try ~ catch와 책임
만약에 예외가 발생했는데 예외 처리를 위한 try ~ catch문이 존재하지 않습니다. 이러한 경우 책임은 어디로 넘어갈까요? 바로 호출한 부분으로 책임이 전달합니다. 예제를 살펴봅시다.
⭐️ PassException.cpp
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
|
#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;
}
return 0;
}
|
cs |
⭐️ PassException.cpp (예외 X)
1
2
3
4
|
두 개의 숫자 입력: 9 2
나눗셈의 몫: 4
나눗셈의 나머지: 1
나눗셈을 마쳤습니다.
|
cs |
⭐️ PassException.cpp (예외 O)
1
2
3
|
두 개의 숫자 입력: 7 0
제수는 0이 될 수 없습니다.
프로그램을 다시 실행하세요.
|
cs |
예외가 처리되지 않으면, 예외가 생한 함수를 호출한 영역으로 예외데이터가 전달된다는 것을 알 수 있습니다.
🌼 예외상황이 발생한 위치 != 예외상황을 처리해야하는 위치인 경우
⭐️ DiffHandlingPosition.cpp
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
32
33
34
35
|
#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[200];
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;
}
|
cs |
⭐️ DiffHandlingPosition.cpp 실행결과
1
2
3
4
5
6
7
8
9
10
11
|
두 개의 숫자 입력: 123 3A5
123 + 3A5 = 문자: A가 입력되었습니다.
재입력 진행합니다.
두 개의 숫자 입력: 28F 211
28F + 211 = 문자: F가 입력되었습니다.
재입력 진행합니다.
두 개의 숫자 입력: 231 891
231 + 891 = 1122
프로그램을 종료합니다.
|
cs |
함수 내에서 예외 데이터를 전달하면 함수를 완전히 빠져나오는 것과 비슷한 효과가 됩니다.
🌼 스택 풀기
스택풀기란 예외가 처리되지 않아서 함수를 호출한 영역으로 예외 데이터가 전달되는 현상을 뜻합니다.
⭐️StackUnwindig.cpp
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
|
#include <iostream>
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;
}
|
cs |
⭐️StackUnwindig.cpp 실행결과
1
2
3
4
|
SimpleFuncOne(void)
SimpleFuncTwo(void)
SimpleFuncThree(void)
예외코드: -1
|
cs |
여기서 함수 호출 순서는 main -> SimpleFuncOne -> SimpleFuncTwo -> SimpleFuncThree입니다. 스택이 해제되는 순서는 그 반대입니다.
자료하지 일치하지 않는 경우에는 어떻게 될까요? 자료형이 일치하지 않아도 예외 데이터는 전달됩니다.
하나의 try 블록과 다수의 catch 블록으로 이루어져 있는 경우도 있습니다 .
⭐️ CatchList.cpp
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#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[200];
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;
}
|
cs |
⭐️ CatchList.cpp 실행결과
1
2
3
4
5
6
7
8
9
10
11
|
두 개의 숫자 입력: 12A 519
12A + 519 = 문자 A가 입력되었습니다.
재입력 진행합니다.
두 개의 숫자 입력: 082 910
082 + 910 = 0으로 시작하는 숫자는 입력 불가.
재입력을 진행합니다.
두 개의 숫자 입력: 123 456
123 + 456 = 579
프로그램을 종료합니다.
|
cs |
🌼 예외상황을 표현하는 예외 클래스의 설계
기본 자료형 데이터 외에 클래스의 객체도 예외 데이터가 될 수 있습니다. 예외 객체는 예외의 발생을 알리는데 사용되는 객체를 가리켜 '예외객체'라 하며, 예외객체의 생성을 위해 정의된 클래스를 '예외클래스라 합니다.
⭐️ ATMSim.cpp
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
#include <iostream>
#include <cstring>
using namespace std;
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;
}
};
int main(void){
Account myAcc("56789-827120", 5000);
try{
myAcc.Deposit(2000);
myAcc.Deposit(-300);
} catch(DepositException &expn){
expn.ShowExceptionReason();
}
myAcc.ShowMyMoney();
try{
myAcc.WithDraw(3500);
myAcc.WithDraw(4500);
} catch(WithdrawException &expn){
expn.ShowExceptionReason();
}
myAcc.ShowMyMoney();
return 0;
}
|
cs |
⭐️ ATMSim.cpp 실행결과
1
2
3
4
5
|
[예외 메시지: -300는 입금불가]
잔고: 7000
[예외 메시지: 잔액 3500, 잔액부족]
잔고: 3500
|
cs |
'𝐏𝐑𝐎𝐆𝐑𝐀𝐌𝐌𝐈𝐍𝐆 > 𝐂++' 카테고리의 다른 글
STL :: 시퀸스 컨테이너(1) (0) | 2020.09.12 |
---|---|
C++ :: STL이란? (0) | 2020.09.08 |
C++ :: 템플릿의 특수화, 인자, 매개변수, 디폴트값 (0) | 2020.09.01 |
C++ :: 템플릿(Template), 클래스 템플릿(class Template) (0) | 2020.08.31 |
C++ :: 디폴트 대입 연산자, 배열의 인덱스 연산자 오버로딩, const 함수 오버로딩 (0) | 2020.08.30 |