C++ · 심층 가이드
C++ 에러 처리 완전 정리
예외와 반환값이라는 두 계열을 함께 쓰는 15개 예제로 안전한 숫자 파싱과 도메인 오류 표현, RAII 기반 정리, 복구 흐름까지 차례로 정리합니다.
C++에는 오류를 알리는 방식이 하나가 아닙니다. 예외, 오류 코드, std::optional, 그리고 그냥 정의되지 않은 동작까지 공존합니다. 어느 쪽을 고를지는 취향이 아니라 호출 빈도와 실패의 성격이 정합니다. 흔히 일어나는 실패는 값으로 돌려주고, 드물고 프로그램 흐름을 끊어야 하는 실패는 예외로 던지는 구분이 실무에서 가장 오래 버팁니다. finally 구문이 없는 것도 의도된 설계로, 그 자리를 소멸자가 대신합니다.
try catch 기본과 사용자 정의 오류로 예외 계층을 잡은 뒤 Result 반환을 보면 두 방식의 대비가 선명해집니다. finally 정리 항목은 문법을 찾는 편이 아니라, 자원을 쥔 객체의 소멸자에 정리를 넣는 RAII 관용구를 익히는 편입니다. 안전한 숫자 파싱과 입력 검증, 다단계 검증은 경계에서 한 번에 막는 구조를 만드는 흐름이고, fallback 값 사용과 recover 흐름이 그 뒤를 받습니다.
숫자 파싱은 함수마다 실패 처리 방식이 전부 다릅니다. std::stoi는 형식이 틀리면 예외를 던지고 범위를 넘으면 또 다른 예외를 던지지만, C 계열의 atoi는 실패해도 조용히 0을 돌려주어 유효한 입력과 구별되지 않습니다. C++17의 std::from_chars는 예외도 할당도 없이 오류 코드와 파싱이 멈춘 위치를 함께 돌려주고 로케일 영향도 받지 않아, 신뢰할 수 없는 입력에는 이쪽이 맞습니다. 그리고 소멸자에서 예외가 빠져나가면 프로그램이 그대로 종료되므로, 정리 코드 안의 예외는 반드시 그 안에서 삼켜야 합니다.
01try catch 기본
C++에서 try catch 기본 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// try catch 기본
#include <exception>
#include <iostream>
#include <stdexcept>
int main() {
try { throw std::runtime_error("boom"); } catch (const std::exception& ex) { std::cout << ex.what() << "\n"; }
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
02사용자 정의 오류
C++에서 사용자 정의 오류 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// 사용자 정의 오류
#include <iostream>
#include <stdexcept>
int require_positive(int value) { if (value <= 0) throw std::runtime_error("positive only"); return value; }
int main() {
std::cout << require_positive(2) << "\n";
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
03입력 검증
C++에서 입력 검증 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// 입력 검증
#include <exception>
#include <iostream>
#include <stdexcept>
int main() {
try { throw std::runtime_error("boom"); } catch (const std::exception& ex) { std::cout << ex.what() << "\n"; }
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
04안전한 숫자 파싱
C++에서 안전한 숫자 파싱 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// 안전한 숫자 파싱
#include <iostream>
#include <stdexcept>
int require_positive(int value) { if (value <= 0) throw std::runtime_error("positive only"); return value; }
int main() {
std::cout << require_positive(4) << "\n";
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
05안전한 나눗셈
C++에서 안전한 나눗셈 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// 안전한 나눗셈
#include <exception>
#include <iostream>
#include <stdexcept>
int main() {
try { throw std::runtime_error("boom"); } catch (const std::exception& ex) { std::cout << ex.what() << "\n"; }
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
06finally 정리
C++에서 finally 정리 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// finally 정리
#include <iostream>
#include <stdexcept>
int require_positive(int value) { if (value <= 0) throw std::runtime_error("positive only"); return value; }
int main() {
std::cout << require_positive(6) << "\n";
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
07오류 다시 던지기
C++에서 오류 다시 던지기 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// 오류 다시 던지기
#include <exception>
#include <iostream>
#include <stdexcept>
int main() {
try { throw std::runtime_error("boom"); } catch (const std::exception& ex) { std::cout << ex.what() << "\n"; }
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
08도메인 오류 표현
C++에서 도메인 오류 표현 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// 도메인 오류 표현
#include <iostream>
#include <stdexcept>
int require_positive(int value) { if (value <= 0) throw std::runtime_error("positive only"); return value; }
int main() {
std::cout << require_positive(8) << "\n";
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
09fallback 값 사용
C++에서 fallback 값 사용 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// fallback 값 사용
#include <exception>
#include <iostream>
#include <stdexcept>
int main() {
try { throw std::runtime_error("boom"); } catch (const std::exception& ex) { std::cout << ex.what() << "\n"; }
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
10assertion
C++에서 assertion 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// assertion
#include <iostream>
#include <stdexcept>
int require_positive(int value) { if (value <= 0) throw std::runtime_error("positive only"); return value; }
int main() {
std::cout << require_positive(10) << "\n";
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
11Result 반환
C++에서 Result 반환 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// Result 반환
#include <exception>
#include <iostream>
#include <stdexcept>
int main() {
try { throw std::runtime_error("boom"); } catch (const std::exception& ex) { std::cout << ex.what() << "\n"; }
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
12다단계 검증
C++에서 다단계 검증 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// 다단계 검증
#include <iostream>
#include <stdexcept>
int require_positive(int value) { if (value <= 0) throw std::runtime_error("positive only"); return value; }
int main() {
std::cout << require_positive(12) << "\n";
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
13로깅 래퍼
C++에서 로깅 래퍼 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// 로깅 래퍼
#include <exception>
#include <iostream>
#include <stdexcept>
int main() {
try { throw std::runtime_error("boom"); } catch (const std::exception& ex) { std::cout << ex.what() << "\n"; }
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
14recover 흐름
C++에서 recover 흐름 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// recover 흐름
#include <iostream>
#include <stdexcept>
int require_positive(int value) { if (value <= 0) throw std::runtime_error("positive only"); return value; }
int main() {
std::cout << require_positive(14) << "\n";
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
15입력 가드
C++에서 입력 가드 개념을 코드로 빠르게 확인하는 에러 처리 예제입니다.
C++ code
// 입력 가드
#include <exception>
#include <iostream>
#include <stdexcept>
int main() {
try { throw std::runtime_error("boom"); } catch (const std::exception& ex) { std::cout << ex.what() << "\n"; }
}실패를 잡는 것에서 끝내지 말고, 기록하고 복구하는 흐름까지 같이 읽는 것이 중요합니다.
에러를 잡기만 하고 아무 처리도 하지 않으면 문제는 숨어 있고 복구는 더 어려워집니다.
정리하며
- atoi는 실패를 0으로 감추고 stoi는 예외를 던집니다. 외부 입력에는 from_chars가 안전합니다
- 소멸자 밖으로 예외가 빠져나가면 프로그램이 종료되므로 정리 코드에서 잡아야 합니다
- finally 대신 RAII를 씁니다. 자원 해제는 소멸자에 넣어 경로에 상관없이 실행시킵니다
- 흔한 실패는 값으로 돌려주고 드문 실패만 예외로 던지는 기준을 팀 안에서 통일합니다
더 깊이 들어가고 싶다면 C++ 학습 라이브러리에서 다른 주제 가이드를 이어서 보거나, 언어 비교에서 같은 개념이 다른 언어에서 어떻게 표현되는지 확인해 보세요.