C++ 초급 - 12. 최신 C++ 기능 소개 (5 - C++23: std::expected 기본 개념)
2025. 2. 22. 18:20ㆍ프로그래밍 언어/C++
📌 12.5 C++23: std::expected 기본 개념
C++23에서는 예외 처리의 새로운 대안으로 std::expected가 도입되었다.
이를 활용하면 오류를 예외가 아닌 값으로 반환하는 방식으로 더 안전하고 예측 가능한 오류 처리가 가능하다.
📌 1. std::expected를 활용한 예외 처리 대체 방법
🔹 (1) 기존 예외 처리 (try-catch)의 문제점
C++에서는 일반적으로 예외(try-catch 블록)를 사용하여 오류를 처리하지만, 예외 기반 오류 처리는 다음과 같은 문제점이 존재한다.
🔹 문제점
- 오류를 throw 하면, 제어 흐름을 추적하기 어렵다.
- 예외 처리는 성능 오버헤드가 발생할 수 있다.
- 코드의 가독성이 떨어지고, 유지보수가 어려워질 수 있다.
💡 예제: 기존 예외 처리 방식 (try-catch)
#include <iostream>
#include <stdexcept>
int divide(int a, int b) {
if (b == 0) {
throw std::runtime_error("0으로 나눌 수 없습니다!");
}
return a / b;
}
int main() {
try {
std::cout << "결과: " << divide(10, 2) << std::endl; // 정상 출력
std::cout << "결과: " << divide(10, 0) << std::endl; // 예외 발생
} catch (const std::runtime_error& e) {
std::cerr << "오류 발생: " << e.what() << std::endl;
}
return 0;
}
🔹 출력 결과
결과: 5
오류 발생: 0으로 나눌 수 없습니다!
🔹 문제점
- throw로 예외를 발생시키면, 제어 흐름이 복잡해지고 디버깅이 어려워짐.
- 예외 발생 시 실행이 중단되며, 예외를 catch하지 않으면 프로그램이 비정상 종료될 수 있음.
🔹 (2) C++23의 std::expected를 활용한 예외 처리 대체
C++23에서는 std::expected를 사용하여 예외를 값으로 반환하는 방식을 제공한다.
즉, 예외를 throw하지 않고, 성공(expected) 또는 실패(unexpected) 상태를 값으로 처리 가능하다.
💡 예제: std::expected를 활용한 예외 처리 대체
#include <iostream>
#include <expected>
std::expected<int, std::string> divide(int a, int b) {
if (b == 0) {
return std::unexpected("0으로 나눌 수 없습니다!");
}
return a / b;
}
int main() {
auto result1 = divide(10, 2);
if (result1) {
std::cout << "결과: " << *result1 << std::endl;
} else {
std::cerr << "오류 발생: " << result1.error() << std::endl;
}
auto result2 = divide(10, 0);
if (result2) {
std::cout << "결과: " << *result2 << std::endl;
} else {
std::cerr << "오류 발생: " << result2.error() << std::endl;
}
return 0;
}
🔹 출력 결과
결과: 5
오류 발생: 0으로 나눌 수 없습니다!
💡 설명
- std::expected<T, E>를 사용하면 T(정상값) 또는 E(오류 메시지)를 반환할 수 있음.
- 예외(throw)를 사용하지 않고, 오류를 값으로 처리하므로 흐름을 쉽게 제어 가능.
- 오류가 발생하면 std::unexpected("오류 메시지")를 반환하여 에러를 저장.
- 정상적인 값이면 *result로 접근, 오류가 있으면 result.error()로 메시지 확인.
📌 2. 오류를 값으로 반환하는 방식의 개념 이해
std::expected는 std::optional과 유사하지만, 오류 정보를 포함할 수 있는 것이 차이점이다.
- std::optional<T> → 값이 있거나 없음을 나타냄 (오류 메시지 X).
- std::expected<T, E> → 값(T)이 있거나, 오류(E)를 포함할 수 있음.
💡 예제: std::expected vs. std::optional
#include <iostream>
#include <optional>
#include <expected>
std::optional<int> divideOptional(int a, int b) {
if (b == 0) return std::nullopt; // 오류 발생 시 null 반환
return a / b;
}
std::expected<int, std::string> divideExpected(int a, int b) {
if (b == 0) return std::unexpected("0으로 나눌 수 없습니다!");
return a / b;
}
int main() {
auto optResult = divideOptional(10, 0);
if (optResult) {
std::cout << "std::optional 결과: " << *optResult << std::endl;
} else {
std::cerr << "std::optional 오류 발생!" << std::endl;
}
auto expResult = divideExpected(10, 0);
if (expResult) {
std::cout << "std::expected 결과: " << *expResult << std::endl;
} else {
std::cerr << "std::expected 오류 발생: " << expResult.error() << std::endl;
}
return 0;
}
🔹 출력 결과
std::optional 오류 발생!
std::expected 오류 발생: 0으로 나눌 수 없습니다!
💡 설명
- std::optional은 오류 메시지를 제공하지 않음.
- std::expected는 오류 내용을 저장하여 사용자에게 더 많은 정보를 제공 가능.
📌 3. 기본적인 사용 예제 소개
🔹 (1) 파일 열기 예제 (std::expected 활용)
💡 예제: 파일이 존재하는지 확인하고 처리
#include <iostream>
#include <fstream>
#include <expected>
std::expected<std::ifstream, std::string> openFile(const std::string& filename) {
std::ifstream file(filename);
if (!file) {
return std::unexpected("파일을 열 수 없습니다: " + filename);
}
return std::move(file);
}
int main() {
auto file = openFile("test.txt");
if (file) {
std::cout << "파일을 성공적으로 열었습니다!" << std::endl;
} else {
std::cerr << "오류 발생: " << file.error() << std::endl;
}
return 0;
}
🔹 출력 결과 (파일이 없을 경우)
오류 발생: 파일을 열 수 없습니다: test.txt
💡 설명
- 파일이 정상적으로 열리면 std::ifstream을 반환.
- 파일이 없으면 std::unexpected("오류 메시지")를 반환하여 예외 없이 오류 처리.
📌 4. 정리
개념 | 설명 |
std::expected<T, E> | 성공(T) 또는 오류(E)를 반환하는 새로운 C++23 기능 |
예외 (try-catch) 대체 | throw 대신 std::expected를 사용하여 오류를 값으로 반환 |
오류 메시지 포함 가능 | std::optional과 다르게 오류 메시지를 저장할 수 있음 |
예외 안전성 강화 | std::expected를 활용하면 흐름을 쉽게 제어 가능 |
파일 처리 및 연산에 활용 가능 | 안전한 파일 열기 및 연산 수행 시 유용 |
'프로그래밍 언어 > C++' 카테고리의 다른 글
C++ 초급 - 추가 내용 (심화 학습) (2 - 파일 입출력 (fstream)) (0) | 2025.02.22 |
---|---|
C++ 초급 - 추가 내용 (심화 학습) (1 - 네임스페이스 (namespace)) (0) | 2025.02.22 |
C++ 초급 - 12. 최신 C++ 기능 소개 (4 - C++20: concepts와 범위 기반 for 개선) (0) | 2025.02.22 |
C++ 초급 - 12. 최신 C++ 기능 소개 (3 - C++17: 구조적 바인딩과 if constexpr) (0) | 2025.02.22 |
C++ 초급 - 12. 최신 C++ 기능 소개 (2 - C++14: 개선된 스마트 포인터) (0) | 2025.02.22 |