8예외 안전성 수준을 설명하고, noexcept가 이동 연산, 컨테이너, 코드 생성에 어떤 영향을 미치는지 설명해 주세요.
예외 안전성 수준은 연산 도중 예외가 발생했을 때 어떤 상태가 보장되는지를 나타냅니다. 기본 보장(basic guarantee)은 상태가 변경될 수는 있지만 불변식(invariant)이 유지되고 리소스 누수가 발생하지 않음을 의미합니다. 강력한 보장(strong guarantee)은 커밋 또는 롤백(commit-or-rollback) 시맨틱을 의미하며, 실패 시 관찰 가능한 상태가 변경되지 않습니다. 무예외 보장(nothrow guarantee)은 연산이 절대 예외를 던지지 않음을 의미합니다. 일반적인 구현 기법으로는 RAII (Resource Acquisition Is Initialization), 임시 객체에서 작업 수행, 복사 후 맞바꾸기(copy-and-swap), 예외를 던질 수 있는 작업이 성공한 후에만 커밋이 일어나도록 상태 변경 순서를 정렬하는 방법 등이 있습니다. `noexcept`는 하나의 계약으로, `noexcept` 함수가 예외를 던지면 `std::terminate`가 호출됩니다. 또한 이는 제네릭 코드와 컨테이너에도 영향을 미칩니다. 예를 들어 재할당 시 `std::vector`는 이동 생성자가 `noexcept`일 때만 요소를 이동할 수 있으며, 그렇지 않은 경우 예외 보장을 유지하기 위해 보통 `std::move_if_noexcept`를 통해 복사를 수행합니다. `noexcept`는 필요한 예외 전파 경로를 줄임으로써 코드 생성이나 최적화에도 도움을 줄 수 있지만, 이는 계약이 올바를 때만 유효합니다.
std::vector<T> v;
// During reallocation, an implementation may effectively do:
T* dest = allocate(new_cap);
for (T& x : old_storage) {
construct(dest++, std::move_if_noexcept(x));
}
AI 코치와 함께 이 질문에 답해 보세요
9실패할 수 있는 연산에서 예외(exception)의 대안으로 사용되는 std::expected 또는 이와 동등한 결과(outcome) 타입을 설명해 주세요.
`std::expected<T, E>`는 성공 값 `T` 또는 명시적 오류 `E` 중 하나를 나타내어, 예외 전파에 의존하는 대신 오류를 함수의 반환 타입 일부로 만듭니다. 이는 파싱, 유효성 검사, 네트워크 호출, 스토리지 조회, 재시도 가능한 백엔드 연산처럼 오류 발생이 예상되고 호출자가 로컬에서 이를 처리해야 하는 연산에 유용합니다. 오류 타입에는 오류 코드, 카테고리, 재시도 가능 여부, 메시지, HTTP/RPC 매핑과 같은 구조화된 정보를 담는 것이 좋습니다. Expected/outcome 타입은 오류를 확인하고 전파하는 방식으로 결합할 수 있으며, C++23 스타일의 API에서는 `and_then`, `transform`, `or_else`와 같은 모나딕(monadic) 연산을 사용해 깊게 중첩된 조건문 없이 여러 단계를 체이닝할 수 있습니다. 예외와 비교했을 때 제어 흐름과 API 계약이 명확해지고 예외가 비활성화된 환경이나 ABI 경계에서도 잘 동작합니다. 다만 프로젝트 정책에 따라 드물게 발생하거나 비지역적이거나 진정으로 예외적인 실패에는 여전히 예외가 적합할 수 있습니다.
enum class Errc { BadRequest, NotFound, Timeout, DbUnavailable };
struct Error {
Errc code;
bool retryable;
std::string message;
};
std::expected<User, Error> load_user(UserId id);
HttpResponse handle(UserId id) {
auto user = load_user(id);
if (!user) {
switch (user.error().code) {
case Errc::BadRequest: return {400, user.error().message};
case Errc::NotFound: return {404, "not found"};
case Errc::Timeout: return {503, "try again"};
case Errc::DbUnavailable: return {503, "service unavailable"};
}
}
return {200, serialize(*user)};
}
AI 코치와 함께 이 질문에 답해 보세요