c++에서는 Exception이 throw 됐을 때 처리되지 않으면(catch 구문을 통해 맞는 catch 구문을 찾을 수 없을 경우) terminate를 호출하고, 이 terminate는 기본으로 abort를 호출한다.
(terminate : http://www.cplusplus.com/reference/exception/terminate/)
보통 이런 경우는 개발자가 실수한 경우이기 때문에 이런 경우에서 조금이라도 도움을 주기 위해서 abort 외에 다른 함수를 호출하여 처리되지 않았음을 알려줄 수 있지 않을까? 해서 쓴다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <stdexcept>
void plus(int * ptr)
{
if(!ptr)
throw std::invalid_argument("argument was nullptr");
//throw 6;
//throw std::exception("error");
*(ptr) += 1;
}
int main()
{
int *p = nullptr;
plus(p);
}
|
cs |
이러한 경우에는 invalid_argument Exception이 throw 됬음에도 처리가 되지 않았기 때문에 terminate가 호출 되고, terminate는 기본적으로 abort를 호출함으로 window 기준으로 실행하였을때의 결과는 다음과 같다.
abort의 설명은 넘어가고, 이 abort를 다른 핸들러로 바꾸고 싶을때, set_terminate함수를 호출할 수 있다.
(set_terminate : http://en.cppreference.com/w/cpp/error/set_terminate);
일단 set_terminate의 파라미터와 리턴값의 타입은 다음과 같이 함수포인터로 정의되어 있다.
typedef void (__CRTDECL* terminate_handler )();
typedef void (__CRTDECL* terminate_function)();
이 말은 set_terminate에 줄 함수는
void [function_name](){
//code...
}
와 같이 void에 인자가 없어야 된다는 뜻이다.
그렇기 때문에 위 예제에 붙여본다면 다음과 같이 될 것이다.
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 <stdexcept>
#include <iostream>
void plus(int * ptr)
{
if(!ptr)
throw std::invalid_argument("argument was nullptr");
//throw 6;
//throw std::exception("error");
*(ptr) += 1;
}
void new_terminate_handler()
{
std::cout << "oh, terminate called" << std::endl;
}
int main()
{
set_terminate(new_terminate_handler);
int * p = nullptr;
plus(p);
}
|
cs |
결과는 다음과 같다.
새로 등록한 함수가 불러진 것을 확인할 수 있다.
리턴값이 std::terminate_handler 타입인 것을 알 수 있는데, 호출할 경우, 이전에 등록되있는 함수가 리턴되거나 등록되지 않았을 경우에는 nullptr가 리턴된다라고 되어있다.
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
|
#include <stdexcept>
#include <iostream>
void plus(int * ptr)
{
if(!ptr)
throw std::invalid_argument("argument was nullptr");
//throw 6;
//throw std::exception("error");
*(ptr) += 1;
}
void new_terminate_handler()
{
std::cout << "oh, terminate called" << std::endl;
}
void test2()
{
std::cout << "tedt2 called" << std::endl;
}
int main()
{
set_terminate(new_terminate_handler);
std::terminate_handler prev_func = set_terminate(test2);
prev_func();
int * p = nullptr;
plus(p);
}
|
cs |
결과는 다음과 같다.
이를 통해서 등록은 1개밖에 안되며, 이미 등록되어있을 경우 이전에 등록되어 있던 함수가 리턴되는 것을 확인할 수 있다.
그래서
main 함수의 내용을
std::terminate_handler prev_func = set_terminate(new_terminate_handler); prev_func();
와 같이 작성하면 abort가 호출된다. 왜냐하면 terminate의 기본 등록되어있는 함수가 abort이기 때문이다.
근데 좀 이상하다. 분명 set_teminate는 "변경"일텐데 위의 예제들은 변경하였음에도 abort가 호출되었다.
https://msdn.microsoft.com/ko-kr/library/t6fk7h29(VS.90).aspx
여기에서 Remarks 항목을 읽어보면
After performing any desired cleanup tasks, termFunction should exit the program. If it does not exit (if it returns to its caller), abort is called.
라고 되어있다. 즉, terminate_handler의 함수에서 무조건 프로그램을 종료해야지, 안그러면 abort가 호출된다는 것이다. 그렇기 때문에
terminate_handler에 exit와 같은 함수를 이용해서 그 함수에서 프로그램을 종료하도록 해야된다는 말이다.
'C.C++ > 코드' 카테고리의 다른 글
thread_group (1) | 2018.04.24 |
---|---|
asio 타이머 핸들링 예제 (2) | 2018.04.17 |
asio io_service 한방이해 (0) | 2018.04.15 |
에러값 리턴 (0) | 2017.05.23 |
assertion (0) | 2017.05.18 |
댓글