본문 바로가기

C

c++ exception 정리

c++에서 exception을 처리함에 있어서 stack unwinding에 대해서 잘 알아야 한다

만약 c++에서 exception이 처리된다면

exception이 raise 되는 순간 함수가 stack에서 사라지며

catch 구문으로 옮겨지게 된다.

따라서 만약에 exception이 발생하는 코드 밑에 메모리 할당을 deallocation 하는 부분이 처리되지 않아서

메모리 leak이 발생할 수 있다.

따라서 스마트 포인터를 잘 사용해야 한다.

 

자세한 내용은 코드에 담아 두었다.

코드 >>

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <iostream>
 
// stack unwinding에 대해서 잘 알아야 한다
// divide(10, 0)을 실행하면 throw가 실행되면서
// divide가 스택에서 없어지고 main 함수 뒤에는 바로
// catch exception이 바로 실행되게 된다.
 
// 만약 임의의 함수 f가 있을때
// f  안에 divide(10, 0)이 있다고 하자
// 그렇다면, divide(10,0)이 스택에서 없어지고
// f도 stack에서 없어지고
// 최종적으로 main 다음에 catch exception이 위치하게 된다
 
// 만약 catch exception이 없다면 main 함수에서 바로
// std::terminate이 실행되면서 프로세스가 종료되게 된다
 
// exception이 던져질 때는 overhead가 발생한다.
 
class Cat {
private:
public:
    Cat()
    {
        std::cout << "cat constructor" << std::endl;
    }
    ~Cat()
    {
        std::cout << "cat destructor" << std::endl;
    }
private:
    int mAge = 10;
};
 
int divide(int a, int b)
{
    if (b == 0)
    {
        //throw std::exception(); // rvalue로 던진다
        throw std::runtime_error("divide by 0");
    }
    return a / b;
};
 
void f()
{
    //Cat* cp = new Cat();
    std::unique_ptr<Cat> cp = std::make_unique<Cat>();
    std::cout << divide(100<< std::endl;
    // Memory Leak이 발생하게 된다.
    // RAII를 준수하자. smart pointer 사용
    //delete cp;
}
 
int cat_divide(int a, int b)
{
    if (b == 0)
    {
        //throw std::exception(); // rvalue로 던진다
        throw Cat();
    }
    return a / b;
};
 
int main()
{
    std::cout << "normal divide" << std::endl;
    try
    {
        std::cout << divide(100<< std::endl;
    }
    catch (const std::exception &e) // reference로 받아야 한다    
    {
        std::cout << e.what() << std::endl;
        std::cout << "exception catched" << std::endl;
    }
    std::cout << "cat divide" << std::endl;
    try
    {
        std::cout << cat_divide(100<< std::endl;
    }
    //catch (const Cat & c) // reference로 받아야 한다
    catch(...) // ...은 모든 exception을 잡는다
    {
        std::cout << "cat exception catched" << std::endl;
    }
 
    // Memory Leak이 발생하게 된다.
    std::cout << "f() divide" << std::endl;
    try
    {
        f();
    }
    catch (const std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }
    return 0;
}