프로그램을 작성하다보면 문법적인 오류가 아니라 논리적인 오류로 프로그램이 의도치 않는 동작을 하는 경우가 있습니다.
예를 들어, 다음과 같이 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 |