학습
C++ C++의 고급 예외 처리
C++ C++의 고급 예외 처리 — 고급
C++의 고급 예외 처리
1. 도입 (왜 배워야 하는가)
C++의 예외 처리는 프로그램의 안정성과 신뢰성을 높이는 중요한 요소입니다. 실무에서는 다양한 상황에서 예외가 발생할 수 있으며, 이를 적절히 처리하지 않으면 프로그램이 비정상적으로 종료되거나 데이터가 손실될 수 있습니다. 예를 들어, 웹 애플리케이션에서는 사용자가 입력한 데이터의 유효성을 체크해야 하고, 데이터베이스 접근 시에도 예외를 처리해야 합니다. 예외 처리를 제대로 구현하지 않으면, 사용자는 오류 메시지를 보게 되고, 이는 사용자 경험에 악영향을 미치게 됩니다.
또한, 고급 예외 처리 기법을 이해하지 못하면 복잡한 시스템에서 발생하는 예외를 효과적으로 관리하기 어렵습니다. 이로 인해 코드가 복잡해지고 유지보수가 어려워지는 문제가 발생할 수 있습니다.
2. 핵심 개념 설명
예외(Exception)
예외는 프로그램 실행 중에 발생하는 비정상적인 상황으로, 이를 처리하지 않으면 프로그램이 종료됩니다. 실생활에서의 예를 들면, 친구와의 약속을 지키지 못했을 때의 상황과 유사합니다. 약속을 지키지 못하면 문제가 발생하고, 이 문제를 해결하기 위해 대처해야 합니다.
try-catch 블록
try 블록은 예외가 발생할 수 있는 코드를 포함하고, catch 블록은 발생한 예외를 처리하는 부분입니다. 이는 마치 비 오는 날 우산을 준비하는 것과 같습니다. 비가 올 때 우산을 펴야 비를 맞지 않듯이, 예외가 발생할 때 catch 블록에서 적절한 처리를 해줘야 합니다.
throw 키워드
throw는 예외를 발생시키는 키워드로, 문제 상황을 알릴 때 사용됩니다. 친구에게 약속에 대한 사정을 설명하는 것과 비슷합니다. "약속을 지킬 수 없다"고 말하는 것은 예외를 던지는 것과 같습니다.
| 용어 | 설명 |
|---|---|
| Exception | 프로그램 실행 중 발생하는 오류 |
| try-catch | 예외를 처리하는 구조 |
| throw | 예외를 발생시키는 키워드 |
3. 기본 코드 예제
다음은 C++에서 기본적인 예외 처리 방법을 보여주는 코드입니다.
#include <iostream>
#include <stdexcept>
void divide(int a, int b) {
if (b == 0) {
throw std::invalid_argument("0으로 나눌 수 없습니다.");
}
std::cout << "결과: " << a / b << std::endl;
}
int main() {
try {
divide(10, 0);
} catch (const std::invalid_argument& e) {
std::cerr << "예외 발생: " << e.what() << std::endl;
}
return 0;
}
실행 결과
예외 발생: 0으로 나눌 수 없습니다.
코드 한 줄씩 동작 설명
#include <stdexcept>: 예외 처리를 위한 표준 라이브러리를 포함합니다.void divide(int a, int b): 두 정수를 나누는 함수를 정의합니다.if (b == 0): 두 번째 인자가 0인지 검사합니다.throw std::invalid_argument(...): 0으로 나누려 할 경우 예외를 발생시킵니다.std::cout << "결과: " << a / b << std::endl;: 나누기 결과를 출력합니다.try { ... } catch { ... }: 예외 발생 가능성이 있는 코드 블록을 감싸고, 발생한 예외를 처리합니다.std::cerr << "예외 발생: " << e.what() << std::endl;: 발생한 예외 메시지를 출력합니다.- 잘못된 코드:
- 올바른 코드:
- 잘못된 코드:
- 올바른 코드:
- C++의 예외 처리는 프로그램의 안정성을 높이는 핵심 요소입니다.
try-catch블록을 사용하여 예외를 효과적으로 처리할 수 있습니다.throw를 사용하여 예외를 발생시킬 수 있습니다.- 실전에서는 파일 입출력과 사용자 입력에서 예외 처리를 자주 사용합니다.
- 예외를 던지지 않거나, 모든 예외를 잡는 것은 피해야 합니다.
- C++의 스마트 포인터와 메모리 관리
- RAII(Resource Acquisition Is Initialization) 패턴
- C++의 템플릿과 메타프로그래밍
4. 실전 활용 예제
1. 파일 입출력에서의 예외 처리
쇼핑몰에서 상품 정보를 파일로 저장하는 경우를 생각해봅시다. 파일이 존재하지 않거나 읽기 권한이 없을 때 예외를 처리할 수 있습니다.
#include <iostream>
#include <fstream>
#include <stdexcept>
void readFile(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
throw std::runtime_error("파일을 열 수 없습니다.");
}
// 파일 처리 코드...
}
int main() {
try {
readFile("nonexistent_file.txt");
} catch (const std::runtime_error& e) {
std::cerr << "예외 발생: " << e.what() << std::endl;
}
return 0;
}
2. 사용자 입력에서의 예외 처리
사용자로부터 나이를 입력받는 프로그램에서, 음수 값을 입력할 경우 예외를 처리할 수 있습니다.
#include <iostream>
#include <stdexcept>
int getAge() {
int age;
std::cout << "나이를 입력하세요: ";
std::cin >> age;
if (age < 0) {
throw std::invalid_argument("나이는 음수가 될 수 없습니다.");
}
return age;
}
int main() {
try {
int age = getAge();
std::cout << "입력한 나이: " << age << std::endl;
} catch (const std::invalid_argument& e) {
std::cerr << "예외 발생: " << e.what() << std::endl;
}
return 0;
}
5. 흔한 실수와 주의사항
실수 1: 예외를 던지지 않는 경우
void divide(int a, int b) {
if (b == 0) {
// throw std::invalid_argument("0으로 나눌 수 없습니다."); // 예외를 던지지 않음
}
std::cout << "결과: " << a / b << std::endl;
}
void divide(int a, int b) {
if (b == 0) {
throw std::invalid_argument("0으로 나눌 수 없습니다.");
}
std::cout << "결과: " << a / b << std::endl;
}
실수 2: catch 블록을 잘못 작성하는 경우
try {
// ...
} catch (...) { // 모든 예외를 잡는 것은 좋지 않음
std::cerr << "모든 예외 발생" << std::endl;
}
try {
// ...
} catch (const std::invalid_argument& e) {
std::cerr << "예외 발생: " << e.what() << std::endl;
}