int f(int x) throw(); // C++98 방식
int f(int x) noexcept(); // C++11 방식
C++98에서는 예외 명세가 위반되면 호출 스택이 f를 호출한 지점에 도달할 때까지 풀리며 그 지점에서 몇 가지 동작이 취해진 후 프로그램 실행이 종료됨
C++11에서는 프로그램 실행이 종료되기 전에 호출 스택이 풀릴 수도 있고 풀리지 않을 수도 있음
호출 스택이 풀리는 것과 풀릴 수도 있는 것의 차이는 컴파일러의 코드 작성에 영향을 미침
noexcept
함수에서 컴파일러의 옵티마이저는 예외가 함수 바깥으로 전파될 수 있다고 해도 실행지점 스택을 풀기 가능 상태로 유지할 필요가 없음
또한 예외가 noexcept
함수를 벗어난다고 해도 noexcept
함수 안의 객체들을 반드시 생성의 반대 순서로 파괴해야 하는 것도 아님
그러나 예외 명세가 throw()
인 함수에는 그러한 최적화 유연성이 없으며, 예외 명세가 아예 없는 함수 역시 마찬가지로 그런 유연성이 없음
대부분의 함수는 예외에 중립적임
예외 중립적 함수는 스스로 예외를 던지지는 않지만 예외를 던지는 다른 함수를 호출할 수 있음
다른 함수가 예외를 던지면 예외 중립적 함수는 그 예외를 그대로 통과시킴
이처럼 그냥 통과하는 예외가 존재할 수 있으므로 예외 중립적 함수는 noexcept
가 될 수 없음
만약 noexcept
로 선언하고 나중에 마음을 바꾸면 클라이언트 코드가 깨질 위험이 생김
noexcept
는 함수의 인터페이스의 일부로 함수의 구현이 예외를 방출하지 않는다는 성질을 오랫동안 유지할 결심이 선 경우에만 함수를 noexcept
로 선언해야 함
기본적으로 모든 메모리 해제 함수와 소멸자는 암묵적으로 noexcept
이기 때문에 직접 선언할 필요 없음
(직접 선언해도 해가 되지는 않지만 일반적으로 키워드를 쓰지 않음)
noexcept
는 함수의 인터페이스의 일부이며 호출자가 noexcept
여부에 의존할 수 있음noexcept
함수는 비noexcept
함수보다 최적화 여지가 큼noexcept
는 이동 연산자들과 swap
, 메모리 해제 함수들 그리고 소멸자에 특히나 유용함noexcept
함수에서는 이런 스택 언와인딩을 준비할 필요가 없기 때문에 컴파일러는 호출 스택을 간단히 처리할 수 있음이 외에도 컴파일러에게 예외 처리와 관련된 메타데이터 및 런타임 동작을 제거할 수 있는 힌트를 줌
컴파일러에서 번역 단위별로 컴파일을 수행한 결과 생성된 파일이 목적 파일인데 그 안에 포함된 것이 목적 코드임
CPU가 실행할 수 있는 형태에 가깝지만 완전한 실행파일은 아님