본문 바로가기
c, c++/c++로 시작하는 객체지향 프로그래밍

16.1~16.4, 16.6~ 예외 처리

by 피스타0204 2024. 6. 18.

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