C++11부터는 함수 정의에 어떤 예외를 던질 지의 사양(specification)을 기술할 수 있다.
throw 구문과 try ... catch 구문이 제대로 짝을 이뤄야 예외 처리가 가능하므로 다소 까다로운 편이다.
우선, 예외 사양과 상관없는 아주 간단한 예외 처리 예제를 살펴본다.
#include <iostream>
#include <stdexcept>
using namespace std;
void my_func() {
throw out_of_range("out of range!");
}
int main(void)
{
try {
my_func();
} catch (exception& e) {
cout << "caught in handler" << endl;
}
return 0;
}
일부러 예외를 발생시키고 그걸 catch하는 예제이다.
이 예제를 C++11, C++14, C++17 중 어떤 환경에서 실행해도 동일하게 동작하는 것을 확인할 수 있다.
caught in handler
#include <iostream>
#include <stdexcept>
using namespace std;
void my_func() throw(out_of_range) {
throw out_of_range("out of range!");
}
int main(void)
{
try {
my_func();
} catch (exception& e) {
cout << "caught in handler" << endl;
}
return 0;
}
my_func()이 out_of_range 예외를 던질 거라는 예외 사양을 선언한 부분이 달라졌다.
환경마다 동작 방식이 조금씩 달라진다.
컴파일 타임 경고없이 실행된다.
caught in handler
컴파일 타임에 다음과 같은 경고가 발생하지만, 실행 결과는 동일하다.
동적 예외 사양이 표준에서 제외되었음을 경고하고 있다.
exception1.cc:6:16: warning: dynamic exception specifications are deprecated in C++11 [-Wdeprecated]
6 | void my_func() throw(out_of_range) {
| ^~~~~
그래도 실행은 잘 된다.
caught in handler
C++17에서는 완전히 표준에서 제외되어 경고가 아닌 컴파일 타임 에러가 발생한다
exception1.cc:6:16: error: ISO C++17 does not allow dynamic exception specifications
6 | void my_func() throw(out_of_range) {
| ^~~~~
컴파일 타임 에러에 해당하므로 실행되지 않았다.
#include <iostream>
#include <stdexcept>
using namespace std;
void my_func() throw() {
throw out_of_range("out of range!");
}
int main(void)
{
try {
my_func();
} catch (exception& e) {
cout << "caught in handler" << endl;
}
return 0;
}
throw()로 선언된 것에 주목할 것
예외 종류가 명시되지 않았기 때문에 try ... catch 구문이 있음에도 불구하고 catch를 하지 못하고 core dump가 발생한다. 환경과 상관없이 동일하다.
terminate called after throwing an instance of 'std::out_of_range'
what(): out of range!
[1] 2349965 abort (core dumped) ./exception1
안타깝게도 C++17에서는 dynamic exception specification이 금지되었기 때문에, 첫번째 예제와 같이 throw 구문없이 함수를 정의하는 방식으로 코드를 작성해야 한다.
C++17에서 예외 사용도 C++ 언어의 타입 시스템에 포함되도록 변경되었다.
void f() noexcept(true)와 void f() noexcept(false)가 서로 다른 타입을 가진다고 보는 것이다.
void my_func1() noexcept(true) {
throw out_of_range("out of range in my_func1!");
}
void (&my_func)() noexcept(false) = my_func1;
그러나 막상 GCC로 컴파일해보면 경고나 에러가 발생하지 않고 있다.