예외 사양(throw, noexcept)(C++)

예외 사양은 함수에서 전파할 수 있는 예외 형식에 대한 프로그래머의 의도를 나타내는 C++ 언어 기능입니다. 예외 사양을 사용하여 함수가 예외에 의해 종료되거나 종료되지 않도록 지정할 수 있습니다. 컴파일러는 이 정보를 사용하여 함수에 대한 호출을 최적화하고, 예기치 않은 예외가 함수를 이스케이프하는 경우 프로그램을 종료할 수 있습니다.

C++17 이전에는 두 가지 종류의 예외 사양이 있었습니다. Noexcept 사양C++11에서 새로 추가되었습니다. 함수를 이스케이프할 수 있는 잠재적 예외 집합이 비어 있는지 여부를 지정합니다. 동적 예외 사양 또는 사양은 C++11에서 더 이상 사용되지 않으며, 별칭noexcept(true)인 경우를 제외하고 throw()C++17 throw(optional_type_list) 에서 제거되었습니다. 이 예외 사양은 함수에서 throw될 수 있는 예외에 대한 요약 정보를 제공하도록 설계되었지만 실제로는 문제가 있는 것으로 밝혀졌습니다. 다소 유용한 것으로 입증된 동적 예외 사양 중 하나는 무조건 throw() 적인 사양이었습니다. 예를 들어 함수 선언은 다음과 같습니다.

void MyFunction(int i) throw();

컴파일러에 함수가 아무 예외도 throw하지 않음을 알립니다. 그러나 함수가 예외를 throw하는 경우 모드에서 /std:c++14 정의되지 않은 동작이 발생할 수 있습니다. 따라서 위의 연산자 noexcept 대신 연산자를 사용하는 것이 좋습니다.

void MyFunction(int i) noexcept;

다음 표에서는 예외 사양의 Microsoft C++ 구현을 요약합니다.

예외 사양 의미
noexcept
noexcept(true)
throw()
이 함수는 예외를 throw하지 않습니다. /std:c++14 모드(기본값) noexceptnoexcept(true) 동일합니다. 선언되거나 호출되는 noexceptnoexcept(true)std::terminate 함수에서 예외가 throw되는 경우 모드로 throw()/std:c++14 선언된 함수에서 예외가 throw되면 결과는 정의되지 않은 동작입니다. 특정 함수가 호출되지 않습니다. 이는 컴파일러가 호출해야 하는 C++14 표준의 차이입니다 std::unexpected.
Visual Studio 2017 버전 15.5 이상: 모드에서 /std:c++17 , noexceptnoexcept(true)throw() 모두 동일합니다. 모드에서는 /std:c++17throw() .에 대한 noexcept(true)별칭입니다. 모드 이상에서는 /std:c++17 이러한 사양 std::terminate 중 하나로 선언된 함수에서 예외가 throw되면 C++17 표준에서 요구하는 대로 호출됩니다.
noexcept(false)
throw(...)
사양 없음
함수는 모든 형식의 예외를 throw할 수 있습니다.
throw(type) (C++14 이하) 함수는 형식 type의 예외를 throw할 수 있습니다. 컴파일러는 구문을 수락하지만 이를 .로 noexcept(false)해석합니다. 모드 이상에서 /std:c++17 컴파일러는 경고 C5040을 실행합니다.

애플리케이션에서 예외 처리를 사용하는 경우 호출 스택에는 throw된 예외를 처리하는 함수가 있어야만 표시된 noexceptnoexcept(true)함수의 외부 범위가 종료됩니다throw(). 예외를 throw하는 함수와 예외를 처리하는 함수 간에 호출된 noexceptnoexcept(true) 함수가 (또는 throw() 모드에서/std:c++17) 지정된 경우 noexcept 함수가 예외를 전파할 때 프로그램이 종료됩니다.

함수의 예외 동작은 다음 요인에 따라 달라집니다.

  • 설정된 언어 표준 컴파일 모드 입니다.

  • C 또는 C++에서 함수를 컴파일하는지 여부

  • /EH 사용하는 컴파일러 옵션입니다.

  • 예외 사양을 명시적으로 지정하는지 여부

C 함수에서는 명시적 예외 사양이 허용되지 않습니다. C 함수는 예외를 throw하지 않는 것으로 간주되며 , /EHa또는 /EHac.에서 /EHsc/EHs구조적 예외를 throw할 수 있습니다.

다음 표에서는 C++ 함수가 잠재적으로 다양한 컴파일러 예외 처리 옵션에서 throw될 수 있는지 여부를 요약합니다.

함수 /EHsc /EHs /EHa /EHac
예외 사양이 없는 C++ 함수
또는 noexcept(true)throw() 예외 사양이 있는 noexceptC++ 함수 아니요 없음
또는 throw(...)throw(type) 예외 사양이 있는 noexcept(false)C++ 함수

예시

// exception_specification.cpp
// compile with: /EHs
#include <stdio.h>

void handler() {
   printf_s("in handler\n");
}

void f1(void) throw(int) {
   printf_s("About to throw 1\n");
   if (1)
      throw 1;
}

void f5(void) throw() {
   try {
      f1();
   }
   catch(...) {
      handler();
    }
}

// invalid, doesn't handle the int exception thrown from f1()
// void f3(void) throw() {
//   f1();
// }

void __declspec(nothrow) f2(void) {
   try {
      f1();
   }
   catch(int) {
      handler();
    }
}

// only valid if compiled without /EHc
// /EHc means assume extern "C" functions don't throw exceptions
extern "C" void f4(void);
void f4(void) {
   f1();
}

int main() {
   f2();

   try {
      f4();
   }
   catch(...) {
      printf_s("Caught exception from f4\n");
   }
   f5();
}
About to throw 1
in handler
About to throw 1
Caught exception from f4
About to throw 1
in handler

참고 항목

try, throwcatch 문(C++)
예외 및 오류 처리에 대한 최신 C++ 모범 사례