[C++] 예외 처리(Exception handling)

2024. 6. 28. 20:58·Programming Language(Sub)/C++

예외 처리(Exception Handling)

  • 예외 Case

    • ex) 파일이 제대로 열리지 않는 경우

    • ex) 데이터 포맷이 맞지 않아 데이터를 받을 수 없는 경우

Factorial을 구하는 함수

#include <iostream>
using namespace std;

int fact(int n) {
    if (n == 0) return 1;
    return n * fact(n - 1);
}

int main() {
    int n;
    cin >> n;
    if (n < 0) {
        cout << n << ": 음수입니다." << endl;
    }
    else {
        cout << n << "!= " << fact(n) << endl;
    }
}
  • 이렇게 사용자가 실수로 음수를 입력할 수 있다.

  • n이 음수인 경우 fact함수가 실행되지 않도록 처리를 해줘야 함

#include <iostream>
using namespace std;

int fact(int n) {
    if (n == 0) return 1;
    return n * fact(n - 1);
}

int main() {
    int n;
    cin >> n;
    try {
        if (n < 0) {
            throw n; // n은 예외 객체
        }
        cout << n << "! = " << fact(n) << endl; 
    }
    catch (int e) {
        cout << e << ": 음수입니다. " << endl;
    }
        // ...
}
  • 예외를 발생할 수 있는 부분을 try 블럭에 넣자

  • 예외가 발생하지 않는다면 cout << n << "! = " << fact(n) << endl; 을 출력하고 catch문 아래로 간다

  • 예외가 발생하면 throw 후 catch문으로 이동하고, throw한 예외 객체를 catch문의 매개변수로 전달하여 catch문 내의 코드를 실행한다

  • 예외에 해당하는 메시지를 만들어서 던져보자

int main() {
    int n;
    cin >> n;
    try {
        if (n < 0) {
            throw to_string(n) + ": 음수입니다."; // n은 예외 객체
        }
        cout << n << "! = " << fact(n) << endl; 
    }
    catch (string e) {
        cout << e << endl;
    }
    // ...
}
  • 여기서 효율을 생각한다면 예외 객체가 이동 생성이 되도록 해줄 수 있다.
int main() {
    /* 생략 */
    catch (const string &e) {
        cout << e << endl;
    }
    // ...
}
  • if문을 사용하지 않고 try-catch를 사용해야 하는 이유?
#include <iostream>
#include <string>
using namespace std;

int fact(int n) {
    if (n == 0) return 1;
    return n * fact(n - 1);
}

int main() {
    int n, r;
    cin >> n >> r;
    try {
        if (n < 0) {
            throw to_string(n) + ": 음수입니다."; // n은 예외 객체
        }
        int a = fact(n);

        if (r < 0) {
            throw to_string(r) + ": 음수입니다."; // n은 예외 객체
        }
        int b = fact(r);

        if (n - r < 0) {
            throw to_string(n - r) + ": 음수입니다."; // n은 예외 객체
        }
        int c = fact(n - r);

        cout << a / b / c << endl; 
    }
    catch (const string &e) {
        cout << e << endl;
    }
    // ...
}
  • 이렇게 factorial을 호출해줄 때마다 throw를 해줘야 한다면 그냥 if문을 사용하는 거에 비해 장점이 하나도 없다

  • 객체를 던지고 받는 과정은 함수 내에서만 일어나는게 아니라, 함수 사이에서도 일어날 수 있다.

#include <iostream>
#include <string>
using namespace std;

int fact(int n) {
    if (n < 0) throw to_string(n) + ": 음수입니다.";
    if (n == 0) return 1;
    return n * fact(n - 1);
}

int main() {
    int n, r;
    cin >> n >> r;
    try {
        int a = fact(n);
        int b = fact(r);
        int c = fact(n - r);

        cout << a / b / c << endl; // 조합(Combination)
    }
    catch (const string &e) {
        cout << e << endl;
    }
    // ...
}
  • fact 함수에서는 예외 객체를 던져주기만 하고, 예외 처리를 의무를 메인 함수에 넘긴다

  • 이렇게 처리 해주면 코드가 되게 간결해진다

  • 조합을 구하는 과정을 comb 함수로 모듈화해보자

#include <iostream>
#include <string>
using namespace std;

int fact(int n) {
    if (n < 0) throw to_string(n) + ": 음수입니다.";
    if (n == 0) return 1;
    return n * fact(n - 1);
}

int comb(int n, int r) {
    int a = fact(n);
    int b = fact(r);
    int c = fact(n - r);
    return a / b / c;
}

int main() {
    int n, r;
    cin >> n >> r;
    try {
        cout << comb(n, r) << endl; 
    }
    catch (const string &e) {
        cout << e << endl;
    }
    // ...
}
  • 조합을 구하는 과정에서 fact()에서 예외가 발생하면 fact() try-catch가 없으므로 comb()로 나오고, comb()에도 try-catch가 없으므로 main으로 나오게 된다. main에 try-catch가 있으므로 main에서 예외처리를 해준다

  • 조합을 여러번 사용자가 구할 수 있도록 while문에 넣어보자

    • while문 안에 try-catch를 넣는 방법과

    • try-catch 안에 while문을 넣는 방법이 있다

  • 두 방법의 차이점에 대해서 확인해보자

int main() {
    int n, r;
    try {
        while (true) {
                cin >> n >> r;
                cout << comb(n, r) << endl; 
        }
    }
    catch (const string &e) {
        cout << e << endl;
    }
    // ...
}
  • try 안에 while문이 있는 경우 while문을 돌 다 예외가 발생하면 while문 밖으로 바로 나가게 된다.

    • 예외가 한 번이라도 발생하면 루프를 빠져나온다
int main() {
    int n, r;
    while (true) {
        try {
            cin >> n >> r;
            cout << comb(n, r) << endl; 
        }
        catch (const string &e) {
            cout << e << endl;
        }
    }
    // ...
}
  • while문 안에 try-catch가 존재하는 경우 예외가 발생해도 while문이 끝나지 않고 계속 루프를 돈다

    • 예외가 발생하더라도 루프를 빠져나오지 않는다
  • catch를 여러 개를 만들 수 있다.

    • 예외를 다루는 클래스를 여러 개를 만들고 예외를 계층적으로 다룰 때, 보통 catch를 여러 개를 만들어 사용한다
int main() {
    int n, r;
    while (true) {
        try {
            throw 123;
            cin >> n >> r;
            cout << comb(n, r) << endl; 
        }
        catch (const string &e) {
            cout << e << endl;
        }
        catch (int e) {
            cout << e << endl;
        }
    }
    // ...
}
  • 프로그램을 실행하면 throw 123을 먼저 만나서 catch (int e)로 진입하게 된다

  • catch에서 잡을 수 없는 에러가 발생한다면?

    • 위 예시에서 double을 throw한다면?
int main() {
    int n, r;
    while (true) {
        try {
            throw 12.3;
            cin >> n >> r;
            cout << comb(n, r) << endl; 
        }
        catch (const string &e) {
            cout << e << endl;
        }
        catch (int e) {
            cout << e << endl;
        }
    }
    // ...
}
  • catch 안으로 들어가지 않아 런타임 에러가 발생한다

  • 다음과 같이 처리할 수도 있다.

int main() {
    int n, r;
    while (true) {
        try {
            throw 12.3;
            cin >> n >> r;
            cout << comb(n, r) << endl; 
        }
        catch (const string &e) {
            cout << e << endl;
        }
        catch (int e) {
            cout << e << endl;
        }
        catch (...) {
            cout << "알 수 없는 예외 발생" << endl;
        }
    }
    // ...
}
  • catch하지 못한다면 swtich문의 default 처럼 catch(...) 으로 진입한다

참조) 두들낙서 C/C++ 강좌

'Programming Language(Sub) > C++' 카테고리의 다른 글

[Modern C++] 함수 객체와 람다식  (0) 2024.06.28
[C/C++] 함수 포인터  (0) 2024.06.28
[C++] 템플릿 특수화와 비타입 파라미터  (0) 2024.06.28
[C++] 함수 템플릿과 클래스 템플릿  (0) 2024.06.28
[C++] 정사각형-직사각형 문제  (0) 2024.06.28
'Programming Language(Sub)/C++' 카테고리의 다른 글
  • [Modern C++] 함수 객체와 람다식
  • [C/C++] 함수 포인터
  • [C++] 템플릿 특수화와 비타입 파라미터
  • [C++] 함수 템플릿과 클래스 템플릿
lumana
lumana
배움을 나누는 공간 https://github.com/bebeis
  • lumana
    Brute force Study
    lumana
  • 전체
    오늘
    어제
    • 분류 전체보기 (457)
      • Software Development (27)
        • Performance (0)
        • TroubleShooting (1)
        • Refactoring (0)
        • Test (8)
        • Code Style, Convetion (0)
        • DDD (0)
        • Software Engineering (18)
      • Java (71)
        • Basic (5)
        • Core (21)
        • Collection (7)
        • 멀티스레드&동시성 (13)
        • IO, Network (8)
        • Reflection, Annotation (3)
        • Modern Java(8~) (12)
        • JVM (2)
      • Spring (53)
        • Framework (12)
        • MVC (23)
        • Transaction (3)
        • AOP (11)
        • Boot (0)
        • AI (0)
      • DB Access (1)
        • Jdbc (1)
        • JdbcTemplate (0)
        • JPA (14)
        • Spring Data JPA (0)
        • QueryDSL (0)
      • Computer Science (130)
        • Data Structure (27)
        • OS (14)
        • Database (10)
        • Network (21)
        • 컴퓨터구조 (6)
        • 시스템 프로그래밍 (23)
        • Algorithm (29)
      • HTTP (8)
      • Infra (1)
        • Docker (1)
      • 프로그래밍언어론 (15)
      • Programming Language(Sub) (77)
        • Kotlin (1)
        • Python (25)
        • C++ (51)
        • JavaScript (0)
      • FE (11)
        • HTML (1)
        • CSS (9)
        • React (0)
        • Application (1)
      • Unix_Linux (0)
        • Common (0)
      • PS (13)
        • BOJ (7)
        • Tip (3)
        • 프로그래머스 (0)
        • CodeForce (0)
      • Book Review (4)
        • Clean Code (4)
      • Math (3)
        • Linear Algebra (3)
      • AI (7)
        • DL (0)
        • ML (0)
        • DA (0)
        • Concepts (7)
      • 프리코스 (4)
      • Project Review (6)
      • LegacyPosts (11)
      • 모니터 (0)
      • Diary (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
lumana
[C++] 예외 처리(Exception handling)
상단으로

티스토리툴바