예외 처리 (Exception Handling)
-
예외(Exception): 프로그램 실행 중 비정상적으로 발생환 상황
-
예외 처리(Exception Handling): 예외를 처리하여 프로그램이 정상적으로 동작하도록 하는 것
-
C++에서는 try ... catch 구문을 사용하여 예외를 처리함.
try {
if (예외 조건)
throw 예외 객체;
} catch (예외 객체) {
예외 처리
}
-
try { } 와 catch { } 는 하나로 사용되어야 함.
-
try 블록에서 처리할 예외를 정의.
-
catch 블록에서 발생한 예외를 처리.
-
-
throw 키워드는 예외를 고의적으로 발생시키는 것.
-
예외가 발생하는 상황: 0으로 나누기 등
#include <iostream>
using namespace std;
int main() {
int a = 9, b = 0, c = a / b;
cout << c << endl;
return 0;
}
/*
$ g++ test.cpp
$ ./a.out
[1] 1884 floating point exception ./a.out
*/
-
예외 처리를 try ... catch 구문으로 하지 않으면 if 문을 사용해야 하므로, 조건문과 예외 처리 코드가 구분되지 않음. 가독성이 떨어짐.
#include <iostream>
using namespace std;
int main() {
int a = 9, b = 0, c = 0;
if (b != 0) {
c = a / b;
cout << c << endl;
} else {
cout << "Exception: Divide by zero" << endl;
}
return 0;
}
-
예외 처리만 명확하게 구분하기 위해 반드시 예외는 try ... catch 구문으로 처리해야 함.
#include <iostream>
using namespace std;
int main() {
int a = 9, b = 0, c = 0;
try {
if (b == 0) throw b;
c = a / b;
cout << c << endl;
} catch (int divided) {
cout << "Exception: Divide by " << divided << endl;
}
return 0;
}
/*
$ g++ test.cpp
$ ./a.out
Exception: Divide by 0
*/
-
예외가 둘 이상일 경우 catch 를 여러 개 사용해서 처리할 수 있음.
try {
if (예외 조건1)
throw 예외 객체1;
if (예외 조건2)
throw 예외 객체2;
} catch (예외 객체1) {
예외 처리
} catch (예외 객체2) {
예외 처리
}
-
함수를 사용해서 예외 처리를 할 경우
#include <iostream>
#include <string>
using namespace std;
int divide(int a, int b) {
if (b == 0)
throw string("Divide by zero");
return a / b;
}
int main() {
int a = 9, b = 0, c = 0;
try {
c = divide(a, b);
cout << c << endl;
} catch (string msg) {
cout << "Exception: " << msg << endl;
}
return 0;
}
-
throw와 noexcept 키워드로 함수의 예외 처리 범위를 지정할 수 있음.
-
void func(int a); 모든 타입의 예외가 발생 가능.
-
void func(int a) throw(int); 정수형 타입 예외만 던질 수 있음.
-
void func(int a) throw(char *, int); 둘 이상의 타입으로 예외를 던질 때는 쉼표(,)로 나열.
-
void func(int a) throw(); 예외가 발생하지 않음.
-
void func(int a) noexcept; 예외가 발생하지 않음 (C++11 style)
-
표준 예외 클래스 (Standard Exception Class)
-
C++에서는 자주 발생하는 예외에 대해 미리 정의한 클래스를 제공함.
-
각각의 예외별로 다른 header 파일에 정의되어 있지만, <exception> 헤더 파일을 포함하면 대부분 사용 가능.
-
대표적인 표준 예외 클래스
-
bad_alloc 메모리 할당 오류로서 new 연산에서 발생 #include <new>
-
bad_cast 형변환 오류로서 dynamic_cast에서 발생 #include <typeinfo.h>
-
bad_type_id typeid에 대한 피 연산자가 널 포인터인 경우 발생
-
bad_exception 예기치 못한 예외로서 함수 발생 목록에 있지 않는 예외
-
bad_logic_error 클래스 논리 오류
-
invalid_argument, length_error, out_of_range 의 기본 #include <stdexcept>
-
runtime_error 실행 오류로 overflow_error와 underflow_error의 기본 #include <stdexcept>
-
#include <iostream>
#include <new>
using namespace std;
int main () {
try {
int* arr= new int[10000000000000000];
delete[] arr;
} catch (bad_alloc& ba) {
cerr << "bad_alloc caught: " << ba.what() << endl;
}
return 0;
}
/*
$ ./a.out
a.out(7097,0x117dcadc0) malloc: can't allocate region
:*** mach_vm_map(size=40000000000000000, flags: 100) failed (error code=3)
a.out(7097,0x117dcadc0) malloc: *** set a breakpoint in malloc_error_break to debug
bad_alloc caught: std::bad_alloc
*/
스택 풀기 (Stack Unwinding)
-
예외가 발생했을 때 catch 를 사용하지 않으면 해당 함수를 호출한 위치로 예외를 전달함.
-
함수 호출 시 정보를 스택에 저장하므로, catch를 만날 때까지 스택에서 함수 정보를 하나씩 꺼내면서 찾아감.
-
예외 처리를 하기 위해 발생 지점부터 처리 위치까지 스택에서 함수를 소멸시키면서 이동.
#include <iostream>
using namespace std;
void fn1() { throw 0; }
void fn2() { fn1(); }
void fn3() { fn2(); }
void fn4() { fn3(); }
int main () {
try {
fn4();
} catch (int e) {
cout << "Exception: " << e << endl;
}
return 0;
}
/*
$ ./a.out
Exception: 0
*/
'Programming Language > C++' 카테고리의 다른 글
표준 템플릿 라이브러리(Standard Template Library) (0) | 2020.11.17 |
---|---|
템플릿(Template) (0) | 2020.11.16 |
객체 지향 프로그래밍(Object-Oriented Programming) - 4 (0) | 2020.11.15 |
객체 지향 프로그래밍(Object-Oriented Programming) - 3 (0) | 2020.11.10 |
객체 지향 프로그래밍(Object-Oriented Programming) - 2 (0) | 2020.11.06 |