Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 예외 처리 프로그램 – try-catch로 다양한 예외 처리하기


복잡한 수학 연산을 수행하는 함수가 있다고 가정해 보겠습니다. 연산 과정에서는 여러 종류의 예외(exception)가 발생할 수 있으며, 우리는 발생 가능한 다양한 유형의 예외를 상황에 맞게 처리해야 합니다. 구체적인 처리 규칙은 다음과 같습니다.

  • 메모리 부족: 컴퓨터가 연산에 필요한 메모리를 할당하지 못하면 'Memory Low!'를 출력합니다.
  • C++ 표준 예외: 그 외의 C++ 관련 예외가 발생하면 'Exception:'을 출력한 뒤 해당 예외의 내용을 함께 출력합니다.
  • 기타 예외: 위 경우에 해당하지 않는 알 수 없는 예외가 발생하면 'Unhandled Exception'을 출력합니다.

값의 쌍(pair)으로 구성된 배열이 입력으로 주어지며, 이 배열을 해당 함수에 전달합니다. 실행 중 예외가 발생하면 앞서 설명한 규칙에 따라 처리하고, 예외가 발생하지 않으면 계산 결과를 그대로 출력합니다.

이때 우리는 예외를 발생시키는 함수의 내부 동작 방식에는 관심을 두지 않고, 오직 예외 처리 로직 자체에만 집중하면 됩니다.

예를 들어 입력이 arr = {{361643035132, 2297873642249}, {-17, 15}}; 와 같다면 출력 결과는 다음과 같습니다.

Memory Low!
Exception: val1 is negative

첫 번째 값 쌍은 크기가 너무 커서 정상적으로 처리할 수 없기 때문에 'Memory Low!'가 출력됩니다. 두 번째 값 쌍의 첫 번째 값은 음수인데, 제공된 함수는 음수 값을 처리할 수 없으므로 'val1 is negative'라는 예외를 발생(throw)시킵니다.

문제 해결 접근 방법

이 문제를 해결하기 위해 다음과 같은 단계를 따릅니다.

  • i := 0부터 시작하여 i < t를 만족하는 동안 i를 1씩 증가시키며 반복합니다.
    • val1 := values[i][0], val2 := values[i][1]로 설정합니다.
    • try 블록 안에서 foo(val1, val2)의 결과를 출력합니다.
    • 메모리 할당에 실패하여 bad_alloc 예외가 잡히면 "Memory Low!"를 출력합니다.
    • 그 외의 표준 C++ 예외 e가 잡히면 "Exception:"과 함께 예외의 상세 내용을 출력합니다.
    • 위 어느 경우에도 해당하지 않는 예외가 잡히면 "Unhandled Exception"을 출력합니다.

예제 코드

아래 구현 예시를 통해 더 자세히 이해해 보겠습니다.

#include <iostream>
#include <exception>
#include <string>
#include <stdexcept>
#include <vector>
#include <cmath>
using namespace std;

class Solution {
private:
    static int value;
public:
    static int foo(long long val1, long long val2) {
        value += 1;
        if(val1 < 0) {
            throw std::invalid_argument("val1 is negative");
        }
        vector<int> vectorList(val1, 0);
        int r = -1, c = sqrt(-1);
        if(val2 == 0) throw 0;
        r = (val1 / val2) * r;
        int ans = vectorList.at(val2);
        return r + val1 - val2 * ans;
    }
    static int getVal() {
        return value;
    }
};
int Solution::value = 0;

void solve(int t, long int values[][2]) {
    for (int i = 0; i < t; i++) {
        long long val1, val2;
        val1 = values[i][0];
        val2 = values[i][1];
        try {
            cout << Solution::foo(val1, val2) << '\n';
        }
        catch (const std::bad_alloc&) {
            cout << "Memory Low!\n";
        }
        catch (const std::exception& e) {
            cout << "Exception: " << e.what() << '\n';
        }
        catch (...) {
            cout << "Unhandled Exception\n";
        }
    }
}
int main() {
    long int arr[][2] = {{361643035132, 2297873642249}, {-17, 15}};
    solve(2, arr);
}

코드 핵심 포인트

이 코드에서 주목해야 할 부분은 catch 블록의 순서입니다. std::bad_alloc은 std::exception을 상속받는 클래스이므로, 만약 std::exception을 받는 catch 블록이 먼저 위치한다면 bad_alloc 예외도 함께 잡혀 버립니다. 따라서 더 구체적인 예외 타입(std::bad_alloc)을 먼저 처리하고, 일반적인 예외(std::exception)를 나중에 처리해야 의도한 대로 동작합니다. 마지막의 catch(...)는 어떤 타입의 예외든 모두 잡는 안전망 역할을 하므로 항상 가장 마지막에 위치해야 합니다.

입력

long int arr[][2] = {{361643035132, 2297873642249}, {-17, 15}};
solve(2, arr);

출력

Memory Low!
Exception: val1 is negative