16.2) 예외 처리 개요
컴파일 상에 문제가 생기는 것이 아니라 런타임 중 일부 코드에 문제가 있는 것을 예외라고 합니다. 이것은 프로그래머가 처리해줄 수 있는 문제입니다. 이런 경우는 제외하고 실행해주세요. 같은 명령을 하는 것이라고 생각합시다.
정수(int)를 0으로 나누거나 a[2] 같이 범위를 벗어난 접근 제어자를 사용할 경우 등이 있습니다.
#include <iostream>
using namespace std;
int main() {
cout << "Enter two integers :";
int number1, number2;
cin >> number1 >> number2;
try {
if (number2 == 0)
throw number1;
cout << number1 << " / " << number2 << " is " << (number1 / number2) << endl;
}
catch (int ex) {
cout << "Exception: an integer " << ex << " cannot be divided by zero" << endl;
}
cout << "End" << endl;
}
16.3 예외 처리의 장점
예외 처리를 하면 프로그램을 종료할 필요 없이 예외 발생을 전달받을 수 있다는 장점이 있습니다. 라이브러리 함수같은 경우 오류를 검출만 하고 오류를 처리하지 못하는 경우가 있습니다.
16.4) 예외 클래스
c++에서는 예외 객체를 생성하고 전달하는 것이 가능합니다. exception헤더에 정의되어 있는 exception 클래스는 사용자가 건드릴 수 있는 runtime_error(overflow_error, underflow_error), logic_error(invalid_argument, length_error, out_of_range)와 컴파일러가 처리하는 bad_cast, bad_typeid, bad_exception등을 제공합니다.
#include <iostream>
#include <stdexcept> //runtime_error, logic_error를 가진 클래스
using namespace std;
int quotient(int number1, int number2) {
if (number2 == 0)
throw runtime_error("Divisor cannot be zero");
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 (runtime_error& ex) {
cout << ex.what() << endl;
}
cout << "end" << endl;
return 0;
}
예외의 설명 문자열을 반환하는 데에는 what함수를 사용했습니다.
bad_alloc 오류는 new클래스에 위치합니다.
#include <iostream>
#include <new>
using namespace std;
int main()
{
try
{
for (int i = 1; i <= 100; i++)
{
new int[70000000];
cout << i << " arrays have been created" << endl;
}
}
catch (bad_alloc& ex)
{
cout << "Exception: " << ex.what() << endl;
}
return 0;
}
bad_cast 오류는 typeinfo클래스에 저장됩니다.
#include <iostream>
#include <typeinfo>
#include "Geometic.h"
using namespace std;
int main()
{
try
{
Rectangle r(3, 4);
Circle& c = dynamic_cast<Circle&>(r);
}
catch (bad_cast& ex)
{
cout << "Exception: " << ex.what() << endl;
}
return 0;
}
그냥 exception클래스로 모두 잡을 수도 있습니다.
#include <iostream>
#include <vector>
#include <stdexcept>
using namespace std;
int main() {
try
{
vector<int> myvector(10);
myvector.at(20) = 100; //out_of_range 예외 발생시킴
}
catch (exception& ex) {
cout << ex.what() << endl;
}
cout << "Execution continues" << endl;
return 0;
}
16.7) 예외 전달
예외 처리는 catch의 순서대로 우선순위가 정해집니다. 따라서 exception처럼 범위가 넓은 예외 객체를 bad_cast 위에 사용하면 bad_cast는 검사되지 않습니다.
16.8) 예외 중계
예외처리기가 예외를 처리할 수 없거나 호출자에게 단순히 예외를 알리고자 할 때, 예외를 rethrow(중계) 할 수 있습니다.
#include <iostream>
#include <stdexcept>
using namespace std;
int f1()
{
try
{
throw runtime_error("Exception in fl");
}
catch (exception& ex)
{
cout << "Exception caught in function fl" << endl;
cout << ex.what() << endl;
throw; // 예외 중계
}
}
int main()
{
try
{
f1();
}
catch (exception& ex)
{
cout << "Exception caught in function main" << endl;
cout << ex.what() << endl;
}
}
16.9) 예외 지정
throw list라고도 하는 예외 지정(exception specification)은 함수가 전달할 수 있는 예외에 대한 목록입니다. 함수가 전달할 수 있는 잠재적 예외를 함수 헤더에게 선언할 수 있습니다. 함수 정의 부분에 throw 예외목록 으로 잠재적 예외를 작성해주어야 합니다.
void check(double side) throw (NonPositiveSideException)
{
if (side <= 0) throw NonPositiveSideException(side);
}
Triangle(double sidel, double side2, double side3) throw (NonPositiveSideException, TriangleException)
{
check(sidel);
check(side2);
check(side3);
if (!isValid (sidel, side2, side3))
throw TriangleException (sidel, side2, side3);
this->side1 = sidel;
this->side2 = side2;
this->side3 = side3;
}
16.2) 예외를 사용하는 시점
간단한 논리 테스트를 처리할 때에는 if(예외 이름)으로 간단하게 처리하는 것이 좋습니다.
checkpoint)
16.1)입력값이 120인 경우 다음 코드의 출력은 무엇인가?
#include <iostream>
using namespace std;
int main()
{
cout << "Enter a temperature: ";
double temperature;
cin >> temperature;
try
{
cout << "Start of try block ..." << endl;
if (temperature > 95) throw temperature;
cout << "End of try block ..." << endl;
}
catch (double temperature)
{
cout << "The temperature is " << temperature << endl;
cout << "It is too hot" << endl;
}
cout << "Continue ..." << endl;
return 0;
}
16.2 만약 입력이 80인 경우, 이전 코드의 출력은 무엇인가?
16.3 만약 이전 코드에서의
catch (double temperature) {
cout << "The temperature is " << temperature << endl;
cout << "It is too hot" << endl;
}
를 다음 코드로 변경할 경우, 오류가 발생하는가?
catch (double)
{
cout << "It is too hot" << endl;
}
발생하지 않는다.
16.4) 예외 처리의 장점은 무엇인가?
예외 처리를 하면 프로그램을 종료할 필요 없이 예외 발생을 전달받을 수 있다는 장점이 있습니다.
16.5 C++의 exception 클래스와 그의 파생 클래스를 설명하여라, bad alloc과 bad_cast 사용의 예를 제시하여라.
16.6 다음 코드에서 입력이 10, 60, 120일 때, 각각의 출력은 무엇인가 ?
#include <iostream>
using namespace std;
int main()
{
cout << "Enter a temperature: ";
double temperature;
cin >> temperature;
try
{
cout << "Start of try block .." << endl;
if (temperature > 95) throw runtime_error("Exceptional temperature");
cout << "End of try block..." << endl;
}
catch (runtime_error& ex)
{
cout << ex.what() << endl;
cout << "It is too hot" << endl;
}
cout << "Continue ..." << endl;
return 0;
}
16.8하나의 throw 문에서 여러 개의 예외를 전달할 수 있는가? try-catch 블록에서 여러 개의 catch 블록을 가질 수 있는가?
16.9 다음 try-catch 블록에서 statement2가 예외를 발생시킨다고 가정하자.
try{
statement1;
statement2;
statement3;
}
catch (Exception1& ex1)
{
}
catch (Exception2& ex2)
{
}
statement4;
다음 질문에 답해보아라.
■ statement3은 실행될 수 있는가?
네
■ 만약 예외를 받지 못할 경우, statement4는 실행되는가?
네
■ 만약 예외를 catch 블록에서 받는 경우, statement4는 실행되는가?
네
16.10 다음 문장에서 statement2가 예외를 발생시킨다고 가정하자.
try
{
statementl;
statement2:
statement3;
}
catch (Exception1& exl)
{
}
catch (Exception2& ex2)
{
}
catch (Exception3& ex3)
{
statement4;
throw;
}
statement5;
다음 질문에 대해 답하여라.
■ 만약 예외를 받지(catch) 못할 경우, statement5는 실행될 수 있는가?
네
■ 만약 예외가 Exception3 유형인 경우, statement4는 실행될 수 있는가? 그리고 statement5는 실행될 수 있는가?
네, 네
'c, c++ > c++로 시작하는 객체지향 프로그래밍' 카테고리의 다른 글
14.1~ 연산자 오버로딩 (1) | 2024.06.18 |
---|---|
13.7~)이진 입출력 (0) | 2024.05.24 |
13.1~ 13.5)파일 입력과 출력 (0) | 2024.05.24 |
15.5~15.9) 상속과 "다형성" (0) | 2024.05.09 |
15.1~15.4, 15.8) 상속 (0) | 2024.05.02 |