→ if-else문을 통해 예외를 인지하게 한 후 직접 throw를 던졌었지만 문제가 생기면 std::exception 클래스를 통해 시스템 상 내부에서 알아서 발생한 예외를 throw 한다.
- 예외(exception)은 프로그램 실행 중에 예기치 않은 상황이나 오류가 발생했을 때 발생하는 이벤트를 가리킵니다. 예외는 프로그램이 비정상적으로 종료되는 것을 방지하고 오류를 처리하는 메커니즘을 제공
→ C++ 표준 클래스로 예외의 여러 종류들을 나타내는 여러 자식 클래스들을 두고 있다.
• runtime_error 클래스, logic_error 클래스 등등 C++ 표준의 exception 클래스 를 상속받고 있다.
#include <iostream>
#include <string>
#include <exception>
int main()
{
try
{
std::string s;
s.resize(-1); // 예외 발생
}
catch (const std::exception & e)
{
std::cout << typeid(e).name() << std::endl;
std::cerr << e.what() << std::endl;
}
return 0;
}
결과
class std::length_error
string too long
설명
- throw 없이도 시스템상 내부에서 알아서 예외 종류에 알맞는 std::exception 클래스의 자식 클래스를 던져 준다.
- 길이에 대한 에러이므로 std::exception 클래스의 자식 클래스 중 하나인 std::length_error 예외 클래스 객체가 던져진다.
- throw std::length_error(s)이 숨겨져 있는 것이나 마찬가지.
- catch (const std::exception & e) 에서 이를 받는다.
- 길이에 대한 에러이므로 std::exception 클래스의 자식 클래스 중 하나인 std::length_error 예외 클래스 객체가 던져진다.
- typeid(e).name()
- “class std::length_error” 출력
(const std::exception& e)
: 괄호 안에 있는 부분은 예외 객체를 받아들이고 처리하기 위한 매개 변수입니다. 이 부분은 여러 부분으로 나눠서 설명가능.
- const: **e**라는 예외 객체를 수정하지 않고 읽기 전용으로 사용하겠다는 것을 나타냅니다. 즉, 예외 객체를 변경하지 않는다는 의미입니다.
- std::exception&: std::exception 클래스나 이 클래스를 상속받은 클래스의 예외를 처리하겠다는 것을 나타냅니다. std::exception은 C++ 표준 라이브러리에서 제공하는 예외 클래스의 기본 클래스이다. 이렇게 하면 모든 std::exception 타입의 예외를 처리할 수 있습니다.
- e: 예외 객체를 나타내는 변수 이름입니다. 이 변수를 통해 예외 객체의 정보에 접근할 수 있습니다.
정리
catch (const std::exception& e)는 std::exception 클래스나 이 클래스를 상속받은 예외를 잡아서 **e**라는 이름의 변수로 처리하겠다는 의미. 예외가 발생하면 이 블록이 실행되고, e 변수를 사용하여 예외 객체의 정보에 접근하거나 출력 가능.
what
- 예외 종류에 맞는 에러 원인 메시지를 리턴하는 기능을 하는 함수이다.
- 에러 메세지를 리턴하므로 리턴 타입은 const char *
- std::exception 클래스의 모든 자식 클래스는 virtual 가상 함수인 what() 함수를 오버라이딩 한다. → 가상함수를 붙이는 이유는 다른 자식에서도 사용할 수 있기 때문
- e.what()
- “string too long” 출력
- std::length_error 클래스에서는 what() 함수를 “string too long” 출력 하도록 오버라이딩 해놨기 때문에 이렇게 나온 것!
- “string too long” 출력
- e.what()
std::exception 상속 받는 사용자 정의 클래스 만들기
- std::exception를 상속 받은 클래스를 정의하고 what 함수를 아래와 같이 오버라이딩 한다.
#include <iostream>
#include <exception>
class DivisionByZeroException : public std::exception {
public:
const char* what() const throw()
{
return "Division by zero exception";
}
};
int main() {
int numerator, denominator;
std::cout << "Enter the numerator: ";
std::cin >> numerator;
std::cout << "Enter the denominator: ";
std::cin >> denominator;
try {
if (denominator == 0) {
throw DivisionByZeroException(); // 사용자 정의 예외 발생
}
int result = numerator / denominator;
std::cout << "Result: " << result << std::endl;
} catch (const DivisionByZeroException& ex) {
std::cerr << "Exception caught: " << ex.what() << std::endl;
}
return 0;
}
const char* what() const 의미를 알아보자
const char* what() const throw();
- what 함수는 std::exception 클래스에서 상속받은 가상 함수이다. 이 함수는 예외 객체에 대한 설명을 문자열로 반환하는 역할을 함. 여기서 **const char *** 형태의 포인터를 반환함.
- const throw()는 이 함수가 예외를 던지지 않음을 나타냄. 즉, what 함수는 예외가 발생했을 때 안전하게 호출될 수 있는 함수입니다.
사용자 정의 예외 클래스를 만들 때 what 함수를 재정의하여 예외 객체에 대한 설명을 제공하거나 사용자 정의한 예외 클래스에 대한 정보를 포함 가능. 이 설명은 예외가 처리될 때 예외 메시지로 출력되거나 로깅되는 데 사용됨.
DivisionByZeroException 클래스의 객체가 예외로 던져질 때 what 함수를 통해 예외 설명을 제공할 수 있다. 이 설명은 예외가 발생한 상황에 대한 정보를 포함하고 있을 것이며, 예외 처리 코드에서 이 정보를 활용 가능.
다중 Catch으로 구현
#include <iostream>
#include <exception>
class DivisionByZeroException : public std::exception {
public:
const char* what() const noexcept override {
return "Division by zero exception";
}
};
class NegativeNumberException : public std::exception {
public:
const char* what() const noexcept override {
return "Negative number exception";
}
};
int main() {
int numerator, denominator;
std::cout << "Enter the numerator: ";
std::cin >> numerator;
std::cout << "Enter the denominator: ";
std::cin >> denominator;
try {
if (denominator == 0) {
throw DivisionByZeroException(); // DivisionByZeroException 예외 발생
}
if (numerator < 0 || denominator < 0) {
throw NegativeNumberException(); // NegativeNumberException 예외 발생
}
int result = numerator / denominator;
std::cout << "Result: " << result << std::endl;
} catch (const DivisionByZeroException& ex) {
std::cerr << "DivisionByZeroException caught: " << ex.what() << std::endl;
} catch (const NegativeNumberException& ex) {
std::cerr << "NegativeNumberException caught: " << ex.what() << std::endl;
} catch (const std::exception& ex) {
std::cerr << "Generic exception caught: " << ex.what() << std::endl;
}
return 0;
}
- 두 가지 예외 유형(DivisionByZeroException 및 NegativeNumberException)을 처리하기 위해 catch 블록이 추가됨.
- 각 catch 블록은 해당 예외 유형을 처리하며, 다른 예외 유형에 대한 처리는 따로 구현되어있다.
- 마지막의 catch (const std::exception& ex) 블록은 모든 예외 유형을 처리하기 위한 일반적인 예외 처리 블록. 이 블록은 다른 catch 블록에서 처리되지 않은 예외에 대한 예외 처리를 담당합니다.
결과
Enter the numerator: 10
Enter the denominator: 2
Result: 5
Enter the numerator: -8
Enter the denominator: 4
NegativeNumberException caught: Negative number exception
Enter the numerator: 6
Enter the denominator: 0
DivisionByZeroException caught: Division by zero exception
글은 이 분의 글에서 공부한 것과 추가적으로 공부한 것으로 작성하였습니다.
C++ Chapter 14.4 : std::exception
'C++ > C++ try catch, throw, what, exception' 카테고리의 다른 글
Try Catch, throw (2) | 2024.01.26 |
---|