본문 바로가기
CPP

CPP Exception - 1

by yongckim 2021. 11. 27.
728x90
반응형

프로그램을 작성하다보면 문법적인 오류가 아니라 논리적인 오류로 프로그램이 의도치 않는 동작을 하는 경우가 있습니다.

 

예를 들어, 다음과 같이 1부터 9의 숫자를 입력받고 해당 숫자를 출력하는 프로그램을 만들어봅시다.

#include <iostream>

using namespace std;

int main() {
	int n;

	cin >> n;
	cout << n << endl;
}

 

위의 프로그램은 1 부터 9까지의 숫자만 넣을 경우 의도대로 잘 동작하지만 그 이상이나 그 이하의 수도 실행이 된다는 문제가 있습니다.

 

이런 상황을 막기 위해서 조건문을 주어 해당 범위의 수만 출력하도록 만들었었습니다.

 

#include <iostream>

using namespace std;

int main() {
	int n;

	cin >> n;
	if (n < 1 || n > 9)
	{
		cout << "1 ~ 9 사이의 수를 입력해주세요" << endl;
		return 0;
	}
	cout << n << endl;
}

 

if문을 이용하여 예외처리를 하는 방법도 좋지만 해당 코드가 프로그램의 논리를 위해 필요한 코드인지 예외처리를 위해 작성한 코드인지 구분하기 힘들 수 있습니다.

 

그리고 위처럼 if문으로 어디서 예외가 발생할지 정확히 알 수 있다면 직접 처리할 수 있지만 어디서 발생할지 예측하기 어려운 상황일 경우 if문으로만 처리하기는 제한될 것 입니다.

 

C++는 이런 상황에서 예외처리를 위해 try, throw, catch라는 문법을 지원합니다.

 

  • try : 예외가 발생할 수 있는 코드를 감싸는 부분입니다.
  • throw : try에서 예외가 발생한다면 throw의 인자를 catch에게 전달하는 역할을 합니다. (생략가능)
  • catch : throw에서 전달한 변수 이용해서 (생략 가능) 정의한 내용으로 예외를 처리합니다.

위의 코드를 try, throw, catch를 이용해서 다음과 같이 예외처리를 할 수 있습니다.

#include <iostream>

using namespace std;

int main() {
	int n;

	try {
		cin >> n;
		if (n < 1 || n > 9)
			throw n;
		cout << n << endl;
	}
	catch(int n) {
		cout << "1 ~ 9 사이의 수를 입력해주세요" << endl;
		cout << "입력된 수 : " << n << endl;
	}
}

위의 코드는 1 ~ 9 사이의 수가 아닐 경우 catch에 정의된 예외처리를 하고 아닐 경우 n의 값을 출력하고 종료하게 됩니다.

 

throw로 catch에 데이터를 보낼 때 자동 형변환이 되지 않습니다!

throw를 사용하여 catch에게 에러 메세지를 전달할 때, 잘못된 데이터 타입을 전달하지 않도록 주의해야 합니다.

 

다음과 같이 예외처리를 할 경우, 자동형변환을 해주지 않으므로 에러가 발생합니다.

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

int main() {
	int n;

	try {
		cin >> n;
		if (n < 1 || n > 9)
			throw "잘못된 수를 입력하였습니다.";
		cout << n << endl;
	}
	catch(string err) {
		cout << err << endl;
	}
}

throw로 보낸 "잘못된 수를 입력하였습니다." 라는 문자열은 char const * 타입이고 catch로 받는 string과 다른 자료형이기 때문에 throw를 받는 catch문이 없어 에러가 발생하게 되어 종료된 것을 볼 수 있습니다.

 

다음과 같이 코드를 수정하면 잘 실행되는 것을 볼 수 있습니다.

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

int main() {
	int n;

	try {
		cin >> n;
		if (n < 1 || n > 9)
			throw "잘못된 수를 입력하였습니다.";
		cout << n << endl;
	}
	catch(char const *err) {
		cout << err << endl;
	}
}

catch는 throw에서 보낸 동일한 자료형을 매개변수로 받는 catch가 실행됩니다.

throw가 상황에 따라 자료형이 달라질 수 있다면 어떻게 할까요? 

 

이럴 때는 올 수 있는 throw의 자료형에 대해 각각의 catch문을 만들어주면 해결 됩니다.

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

int main() {
	int n;

	try {
		cin >> n;
		if (n == 1)
			throw 1;
		else if (n == 2)
			throw 1.0;
	}
	catch(int n) {
		cout << "정수 전달" << endl;
	}
	catch(double n) {
		cout << "실수 전달" << endl;
	}
}

위의 코드를 실행시키고 1을 입력하면 정수 전달이 출력되고 2를 입력하면 실수 전달이 출력되는 것을 볼 수 있습니다.

모든 자료형을 받는 catch

만약에 발생할 수 있는 자료형이 여러개인데 어떤 자료형이 들어오든 같은 에러처리를 해야한다고 하더라도 전부 하나하나 예외처리를 해야할까요?

 

이런 경우 catch(...)과 같은 형태로 받으면 해결됩니다.

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

int main() {
	int n;

	try {
		cin >> n;
		if (n == 1)
			throw 1;
		else if (n == 2)
			throw 1.0;
		else
			throw "error";
	}
	catch(...) {
		cout << "Exception occurred!" << endl;
	}
}

throw를 통해 catch에 서로 다른 자료형이 전달되더라도 abort가 발생하지 않고 Exception occurred!가 출력되는 것을 볼 수 있습니다.

catch(...)를 사용할 때 주의할 점은 다른 catch문 보다 나중에(가장 마지막에) 나와야 합니다.

 

그렇지 않은 경우 catch(...)안의 코드로 예외처리 되는 상황이 발생하기 때문입니다.

반응형

'CPP' 카테고리의 다른 글

CPP Standard Template Library - iterator  (0) 2021.12.11
CPP Template  (0) 2021.12.09
CPP Casts  (0) 2021.12.04
CPP Exception - 3  (0) 2021.11.28
CPP Exception - 2  (0) 2021.11.28