본문 바로가기
개발/C++

16장 예외처리

by 민돌이2 2021. 12. 9.

한성대학교 김설현교수님 강의내용을 바탕으로 작성함

예외(exception)

프로그램의 실행 동안 발생하는 비정상적인 상황을 의미한다.

예외처리는 프로그램이 예외적인 상황에 대처하고 정상적으로 실행될 수 있도록 한다.

C++에서는 예외를 전달(thorw)하고, 받으며(catch), 처리(process)하는 방법으로 예외를 처리한다.

 

만약 아래와 같은 코드가 있다고 생각해보자

int main() { ‌​​cout << "Enter two integers: "; ‌​​int number1, number2; ‌​​cin >> number1 >> number2; //number1, number2 값을 받음 ‌​​cout << number1 << " / " << number2 << " is " << (number1 / number2) << endl; ​​​​ ‌​​return 0; }

만약 number2를 0으로 입력했다면?

분모는 0이 될수 없기에 오류가 발생하는데, if문을 추가해 에러를 처리할 수 있다.

int main() { ‌cout << "Enter two integers: "; ‌​​int number1, number2; ‌​​cin >> number1 >> number2; ‌​​if (number2 != 0) ‌‌​​​​cout << number1 << " / " << number2 << " is " << (number1 / number2) << endl; ‌​​else //예외처리 ‌‌​​​​cout << "Divisor cannot be zero" << endl; ​​​​ ‌​​return 0; }

이를 C++에서는 throw문을 사용하여 전달하고 try-catch를 사용하여 처리할 수있다.

try { try할 코드; throw 문 또는 throw를 사용하는 함수 try할 다른 코드; } catch (type ex) { ‌예외처리 코드; }

이를 코드에 적용한다면

int main() { ‌cout << "Enter two integers: "; int number1, number2; ‌cin >> number1 >> number2; try { ‌‌if (number2 == 0) //number2를 throw해도 됨 ‌‌‌throw number1; ‌‌cout << number1 << " / " << number2 << " is " << (number1 / number2) << endl; } catch (int ex) { ‌‌cout << "Exception: " << ex << "cannot be devided by 0 " << endl; } ‌cout << "execution continues…" << endl; return 0; }

혹은

int quotient(int number1, int number2) { if (number2 == 0) ‌‌throw number1; return number1 / number2; } int main() { ‌cout << "Enter two integers: "; int number1, number2; ‌cin >> number1 >> number2; try { ‌‌int result = quotient(number1, number2); ‌‌cout << number1 << " / " << number2 << " is " << result << endl; } catch (int ex) { ‌‌cout << "Exception: " << ex << " cannot be divided by 0" << endl; } ‌cout << "Execution continues ..." << endl; return 0; }

 

예외 클래스

catch블록으로 좀 더 많은 정보를 제공하고 싶을 때는 클래스 유형이 더 유용할 수 있다.

C++에서는 예외 객체를 생성할 수 있는 표준클래스들을 제공한다.

exception클래스는 <exciption>헤더에 정의되어 있으며 가상함수 what()을 포함하고 있다.

<stdexcept>헤더에 정의되어 있는 runtime_error는 실행 오류를 설명하고, logic_error는 논리 요류를 설명한다.

bad_alloc, bad_cast, bad_typeid, bad_exception 클래스는 연산자에 의해 throw(전달)되는 예외로 각각 <new>, <typeinfo>, <typeinfo>, <exception> 헤더에 포함되어 있다.

 

예외 지정

전달 목록(throw list)이라고 하는 예외 지정(execption specification)은 함수가 전달할 수 있는 예외에 대한 목록이다.

함수는 전달할 수 있는 예외의 경고를 제공함으로써, 프로그래머가 try-catch블록에서 이런 잠재적인 예외를 처리할 수 있는 프로그램을 작성할 수 있다.

double getArea(double radius) throw (invalid_argument) { if (radius < 0) ‌‌throw invalid_argument("Radius cannot be negative."); return radius * radius * 3.14159; } int main() { ‌cout << "Enter radius: "; double radius; ‌cin >> radius; try { ‌‌double result = getArea(radius); ‌‌cout << "The area is " << result << endl; } catch (invalid_argument& ex) { ‌‌cout << ex.what() << endl; } ‌cout << "Execution continues ..." << endl; return 0; }

 

사용자 예외 클래스

C++는 표쥰 예외 클래스들을 제공하므로, 자신만의 예외 클래스를 작성하는 것보다 가능하면 C++ 표준 예외 클래스를 사용한다.

그러나 만일 표준 예외 클래스로 기술할 수 없는 문제가 발생한다면, 사용자가 직접 예외 클래스를 생성할 수있다.

이 클래스도 다른 C++클래스와 같은 것이긴 하지만, exception클래스에서의 공통적 특징(what() 함수)을 이용할 수 있도록 exception이나 exception의 파생 클래스로부터 파생시키는 것이 바람직하다.

TriangleException.h

#ifndef TRIANGLEEXCEPTION_H #define TRIANGLEEXCEPTION_H #include <stdexcept> using namespace std; class TriangleException : public logic_error { public: TriangleException(double side1, double side2, double side3) ‌‌: logic_error("Invalid triangle") { ‌‌this->side1 = side1; ‌‌this->side2 = side2; ‌‌this->side3 = side3; } double getSide1() const { return side1; } double getSide2() const { return side2; } double getSide3() const { return side3; } private: double side1, side2, side3; }; #endif

Triangle.h

#ifndef TRIANGLE_H #define TRIANGLE_H #include "TriangleException.h" class Triangle { public: Triangle() { side1 = side2 = side3 = 1; } Triangle(double side1, double side2, double side3) { ‌‌if (!isValid(side1, side2, side3)) ‌‌‌throw TriangleException(side1, side2, side3); ‌‌this->side1 = side1; ‌‌this->side2 = side2; ‌‌this->side3 = side3; } double getPerimeter() const { return side1 + side2 + side3; } private: bool isValid(double side1, double side2, double side3) const { ‌‌return (side1 < side2 + side3) && (side2 < side1 + side3) && (side3 < side1 + side2); } private: double side1, side2, side3; }; #endif

main.cpp

#include <iostream> #include "Triangle.h" using namespace std; int main() { try { ‌‌Triangle triangle1(3, 3, 1); ‌‌cout << "Perimeter is " << triangle1.getPerimeter() << endl; ‌‌Triangle triangle2(9, 3, 1); ‌‌cout << "Perimeter is " << triangle2.getPerimeter() << endl; } catch (TriangleException& ex) { ‌‌cout << ex.what(); ‌‌cout << " three sides are " << ex.getSide1() << " " << ex.getSide2() << " " << ex.getSide3() << endl; } return 0; }

 

다중 예외와 예외 처리기의 순서

C++에서는 여러 유형의 예외를 받기 위해 try블록 이후에 여러 개의 catch블록을 추가하는 것이 가능하다.

catch블록에서 지정된 예외들의 순서는 중요하다.

기본 클래스 유형의 catch블록은 파생 클래스 유형의 catch블록 뒤에 나타나야 한다.

(상위 클래스 일 수록 아래로, 자식 클래스가 아래에 있으면 자식 클래스로 가질 않는다.)

다중 예외와 예외 처리기의 순서

 

728x90

'개발 > C++' 카테고리의 다른 글

C++ 클래스 메모리 할당 정리  (0) 2021.12.27
15장 상속과 다형성  (0) 2021.12.09
14장 연산자 오버로딩  (0) 2021.12.09
13장 파일 입력과 출력  (0) 2019.05.21
12장 템플릿, 벡터, 스택  (0) 2019.05.13
11장 포인터와 동적 메모리 관리(후)  (0) 2019.05.09
11장 포인터와 동적 메모리 관리(전)  (0) 2019.05.08
10장 객체 지향 개념  (0) 2019.02.11

댓글