💻 개인공부 💻/C | C++

[C++] 예외 처리 (Exception)

공대생 배기웅 2020. 6. 21. 04:48
반응형

출처 => C++ How to Program (Detitel / Prenticehall) / 현재 그리고 미래지향적인 C++ 프로그래밍(장석우, 임정목 / 비앤씨에듀케이션)

예외란 무엇인가?

▶ 프로그램을 실행 중, 오작동이나 결과에 영향을 미치는 예상치 못한 상황이 발생한다. 이런 사오항을 예외 발생이라고 하는데 이를 처리하는 코드를 예외 처리기라고 한다. 

▶ 예를 들면 다음과 같은 상황이다. 

#include<iostream>
using namespace std;

int getExp(int base, int exp) {
	int value = 1;
	for (int n = 0; n < exp; n++) {
		value = value * base;
//거듭제곱. base를  exp번 곱한 값이 value
	}
	return value;
}

void main() {
	int v = getExp(2, 3);
	cout << "2의 3승은" << v << "입니다" << endl;

	int e = getExp(2, -3);
	cout << "2의 -3승은 " << e << "입니다" << endl;//오류 발생!
}

 

오류가 발생한다!!!! 2의 -3은 1/8인데 이런 기초적인 실수를 컴퓨터가 하다니....! 이렇게 예상치도 못한 오류가 발생하는 경우를 대비하기 위해 예외 처리기를 사용한다. 

▶ 지금까지 공부했던 걸로 이런 상황을 해결할 수 있는데 방법은 2가지 정도이다. if문을 사용하는 방법과 참조 매개변수를 사용하는 방법이다. 

 

1. if문과 리턴값을 이용한 오류처리 예제

#include<iostream>
using namespace std;

int getExp(int base, int exp) {
//base의 exp지수승 계산
	if (base <= 0 || exp <= 0) {
//음수의 계승이거나 양수의 음수 승
		return -1;//오류 리턴
	}
	int value = 1;
	for (int i = 0; i < exp; i++) {
		value = value * base;
	}
	return value;
}

void main() {
	int v = getExp(2, 3);
	cout << "2의 3승은" << v << endl;

	int e = getExp(2, -3);
	if (e != -1) {
		cout << "2의 3승은" << e << endl;
	}
	else cout << "오류입니다. " << endl;
}

 

2. 리턴 값과 참조 매개 변수를 이용한 오류 처리

#include<iostream>
using namespace std;

bool getExp(int base, int exp, int& ret) {
	//참조 매개변수인net
	if (base <= 0 || exp <= 0)
		return false;

	int value = 1;
	for (int i = 0; i < exp; i++) {
		value = value * base;
	}
	ret = value;
	return true;
}

void main() {
	int v = 0;
	if (getExp(2, 3, v))//만약 true라면
		cout << "2의 3승은" << v << endl;
	else cout << "오류입니다." << endl;

	int e = 0;
	if (getExp(2, -3, e))
		cout << "2의 -3승은" << e << endl;
	else cout << "오류입니다" << endl;
}

 

 

2. 예외 기본 처리 형식(feat. try, throw, catch)

▶ 예외 처리를 할 때는 세 가지의 문법 용어가 필요한데 그것이 바로 try, throw, 그리고 catch 문이다.

try { }블록 => 예외가 발생할 가능성이 있는 코드를 묶음

throw { }블록 => 예외가 발견되었을 때 예외 발생을 알리는 문장

catch { }블록 => throw에 의해 발생할 예외를 처리하는 코드를 묶음

 

 

▶ 예제를 통해서 예외 처리문이 어떻게 쓰이는지 알아보자 

 

#include<iostream>
using namespace std;

void main() {
	int n, sum, average;

	while (true) {
		cout << "합을 압력하세요>";
		cin >> sum;
		cout << "인원수를 입력하세요>";
		cin >> n;
		try {
			if (n <= 0)
				throw n;
			else average = sum / n;
		}
		catch (int x) {
			cout << "예외 발생!" 
            << x << "으로 나눌 수 없음" << endl;
			average = 0;
			cout << endl;
			continue;
		}
		cout << "평균=" << average << endl << endl;
	}
}

▶ 위의 소스에서 try문에 대해서 자세히 알아보도록 하자

 

try{
	if(n<=0)
    	throw n;
    else average=sum/n;
}

▶ 예외가 발생할 수도 있는 코드를 나타낸 try문이다. 인원수가 0이거나 음수이면 나누는 것이 불가능하므로 이에 대한 예외를 고려하여 작성하였다. 

 

catch (int x) {
			cout << "예외 발생!" << x << "으로 나눌 수 없음" << endl;
			average = 0;
			cout << endl;
			continue;
		}

▶ 만약 사용자가 n에 음수나 0을 입력했다면 아래의 문장이 실행된다. 

 

▶ 이처럼 예외 처리문을 이용하여 코드를 작성하면 코드가 보다 더 직관적으로 보이게 된다.

▶ 아까 위에서 언급한 예제를 try-catch문을 이용하여 다시 작성해보도록 하겠다.

 

#include<iostream>
using namespace std;

int getExp(int base, int exp) {
	if (base <= 0 || exp <= 0) {
		throw"음수 사용 불가";
	}
	int value = 1;
	for (int i = 0; i < exp; i++) {
		value = value * base;
	}
	return value;
}

void main() {
	int v = 0;
	try {
		v = getExp(2, 3);
		cout << "2의 3승은" << v << "입니다" << endl;
		
		v = getExp(2, -3);
		cout << "2의 -3승은" << v << "입니다" << endl;
	}
	catch (char* s) {
		cout << s << endl;
	}
}

 

 

예외 클래스 만들기

▶ 예외 클래스는 예외 정보를 포함한다. throw로 객체를 던지는데 객체가 복사되어 예외 파라미터에 전달을 한다.

#include<iostream>
#include<cstring>
using namespace std;

class MyException {
	int lineNo;
	string func, msg;
public:
	MyException(int n, string f, string m) {
		this->lineNo = n;
		this->func = f;
		this->msg = m;
	}
	void print() {
		cout << func << ":" << lineNo << "," << msg << endl;
//예외를 설명해주는 메소드
//
	}
};

class DivideByZeroException :public MyException {
//0으로 나누는 예외 클래스 선언
public:
	DivideByZeroException(int lineNo, string func, string msg)
		: MyException(lineNo, func, msg) {}
};

class InvalidInputException :public MyException {
//잘못된 입력 예외 클래스 선언
public:
	InvalidInputException(int lineNo, string func, string msg)
		: MyException(lineNo, func, msg) {}
};

void main() {
	int x, y;
	try {
		cout << "나눗셈을 합니다. 두 개의 양의 정수를 입력하세요>>";
		cin >> x >> y;
		if (x < 0 || y < 0)
			throw InvalidInputException(32, "main()", "음수 입력 예외 발생");
//InvalidInputException 메소드를 던짐.
		if (y == 0)
			throw DivideByZeroException(34, "main()", "0으로 나누는 예외 발생");
//DivideByZeroException 메소드 던짐
		cout << (double)x / (double)y;
//만약 아무런 예외(if 문)에도 포함이 되지 않는다면 나눈 결과를 출력
	}
	catch (DivideByZeroException& e) {
//DivideByZeroException의 객체인 e를 생성하고 print()메소드 던짐
		e.print();
	}
	catch (InvalidInputException& e) {
//InvalidInputException의 객체인 e를 생성하고 print()메소드 던짐
		e.print();
	}
}

 

 

예외처리를 이용한 추가 Example

 

1. 예외 처리를 이용한 퀴즈 Example

#include<iostream>
using namespace std;

void main() {
	
	while (1) {
	int a = (int)(rand() % 100);
	//0에서 100까지의 수 중 임의로 하나 선택(랜덤함수)
	int b = (int)(rand() % 100);
	//0에서 100까지의 수 중 임의로 하나 선택(랜덤함수)
	
	int result = a + b;
	int answer;//사용자가 입력하는 값

	cout << "문제를 내겠습니다" << endl;
	cout << a << "+" << b << "= ?" << endl;
	cin >> answer;
	try {
		if (result != answer)//만약에 정답이 아니라면
			throw answer;//answer를 int n에 대입하여 throw하여라
		else cout << "정답입니다!" << endl;
		//만약 정답이면 정답이라는 것을 출력!
	}
	catch (int n) {//answer로 throw한 것을 받아서 
		cout << n << "은 오답입니다." << endl;
		//오답이라는 것을 출력!
	}
}
}

728x90
반응형