티스토리 뷰
C++에서의 예외 처리
예외 발생시키기 - throw
C++ 에서는 throw를 통해 예외가 발생하였다는 것을 명시적으로 나타낼 수 있다.
위과 같이 throw 로 예외로 전달하고 싶은 객체를 써주면 된다.
C++ 표준에는 out_of_range, overflow_error, length_error, runtime_error 등등 여러가지가 정의되어 있고 표준 라이브러리에서 활용한다.
예외를 throw 하게 되면, throw 한 위치에서 즉시 함수가 종료되고, 예외 처리하는 부분까지 점프하게 된다. 따라서 throw 밑에 있는 모든 문장은 실행되지 않는다. 한 가지 중요한 점은
예외 throw -> 즉시 함수 종료 -> 예외 처리하는 부분까지 점프 (catch)
의 과정을 거치므로 throw 밑에 있는 모든 문장은 실행되지 않는다.
이렇게 함수에서 예외 처리하는 부분에 도달하기 까지 함수를 빠져나가면서, stack 에 생성되었던 객체들을 빠짐없이 소멸시켜 주는데, 덕분에 예외가 발생하여도 사용하고 있는 자원들을 제대로 소멸시킬 수 있다. (소멸자만 제대로 작성하였다면)
try-catch
여기서 catch 문은 throw 된 예외를 받는 부분이다.
catch 문 안에 정의된 예외의 꼴에 맞는 객체를 받게 된다.
위의 Vector 의 경우 out_of_range 를 throw 하였으니 catch 문에서는 out_of_range 를 받아야 한다.
스택 풀기 (stack unwinding)
throw가 발생했을 때 catch 로 점프 하면서 스택 상에서 정의된 객체들을 소멸시키는 과정을 스택 풀기(stack
unwinding)라고 한다.
#include <iostream>
#include <stdexcept>
class Resource {
public:
Resource(int id) : id_(id) {}
~Resource() { std::cout << "리소스 해제 : " << id_ << std::endl; }
private:
int id_;
};
int func3() {
Resource r(3);
throw std::runtime_error("Exception from 3!\n");
}
int func2() {
Resource r(2);
func3();
std::cout << "실행 안됨!" << std::endl;
return 0;
}
int func1() {
Resource r(1);
func2();
std::cout << "실행 안됨!" << std::endl;
return 0;
}
int main() {
try {
func1();
} catch (std::exception& e) {
std::cout << "Exception : " << e.what();
}
}
실행 결과
리소스 해제 : 3
리소스 해제 : 2
리소스 해제 : 1
Exception : Exception from 3!
단, 생성자에서 예외가 발생 시에 소멸자가 호출되지 않는다. 따라서, 만일 예외를 던지기 이전에 획득한 자원이
있다면 catch 에서 잘 해제시켜 줘야만 한다.
여러 종류의 예외 받기
int func(int c) {
if (c == 1) {
throw Parent();
} else if (c == 2) {
throw Child();
}
return 0;
}
int main() {
int c;
std::cin >> c;
try {
func(c);
} catch (Parent& p) {
std::cout << "Parent Catch!" << std::endl;
std::cout << p.what();
} catch (Child& c) {
std::cout << "Child Catch!" << std::endl;
std::cout << c.what();
}
}
이렇게 throw 를 여러번 던지고, 여러개의 catch 로 받을 수 있다.
파생 클래스를 사용할 경우 기반 클래스 겹치지 않도록 주의해야함.
( 위와 같은 상황에선 Child 를 catch하는 코드가 불리지 않는다. Parent catch 를 Child catch 보다 뒤에 써주는 것이 좋다. )
모든 예외 받기
catch(...) 에서 try 안에서 발생한 모든 예외들을 받게 됩니다.
예외를 발생시키지 않는 함수 - noexcept
int foo() noexcept {}
컴파일러는 noexcept 키워드가 붙은 함수는 예외를 발생시키지 않는구나 라고 곧이곧대로 믿고, 그대로 컴파일 하게 된다.대신 noexcept 로 명시된 함수가 예외를 발생시키게 된다면 예외가 제대로 처리되지 않고 프로그램이 종료된다. 컴파일러가 어떤 함수가 절대로 예외를 발생시키지 않는다는 사실을 안다면, 여러가지 추가적인 최적화를 수행할 수 있다.
C++ 11 에서 부터 소멸자들은 기본적으로 noexcept 이다. 절대로 소멸자에서 예외를 던지면 안됨!!
https://cplusplus.com/reference/stdexcept/
https://cplusplus.com/reference/stdexcept/
cplusplus.com
'개발 > C++' 카테고리의 다른 글
[ 씹어먹는 C++ ] 스마트 포인터 (unique_ptr/ shared_ptr/ weak_ptr) (0) | 2024.09.22 |
---|---|
[씹어먹는 C++] 우측값 레퍼런스/ 이동 생성자/ Move 문법/ 완벽한 전달 (0) | 2024.09.20 |
[ 씹어먹는 C++ ] 10. C++ STL (3) | 2024.09.01 |
씹어먹는 C++ 공부하기 (9~) (0) | 2024.08.04 |
씹어먹는 C++ 공부하기 (0) | 2024.05.16 |
- Total
- Today
- Yesterday
- mutex
- 유니티
- SpinLock
- 세마포
- Java
- 유니티슈팅게임
- StartActivityForResult
- NotFoundException: String resource ID #0x0
- 동기화
- unorderedset
- Unity
- Vector
- 스핀락
- 뮤텍스
- unorderedmap
- semaphore
- ARface
- 게임개발
- C++
- map
- 안드로이드스튜디오
- 포톤
- registerForActivityResult
- 광유다
- unityAR
- list
- dependencyResilutionManagement
- 바이너리세마포
- photon
- 지크슈
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |