문서의 임의 삭제는 제재 대상으로, 문서를 삭제하려면 삭제 토론을 진행해야 합니다. 문서 보기문서 삭제토론 C++ (문단 편집) ===== 예외 ===== 예외도 마찬가지로, 설계상 예외 핸들러를 찾기 위해 (RTTI와 동일한 맥락으로) 던져지는 예외의 유형별로 형변환을 해야 하기 때문에 런타임 타입 정보가 필요하다. 따라서 예외를 던질 때마다 적지 않은 성능 패널티가 부과된다. 심지어 예전에는 {{{try}}} 블럭을 설치하는 것과, 소멸자가 있는 클래스를 정의하는 것만으로도 프로그램 성능이 크게 하락했었다. 최신 컴파일러는 zero-cost exception[* 예외를 던지지 않는 실행경로에서는 아무 것도 하지 않아도 되도록 만드는 기법. 요약하면 컴파일러가 전역 예외 핸들러 테이블을 미리 만들어두어, 예외를 던지면 런타임에 해당 테이블을 참조하여 처리하는 방법이다. 이를 구현한 방법은 주로 [[https://patents.google.com/patent/US6247169B1/|SEH]](MSVC 런타임)와 [[https://gcc.gnu.org/wiki/Dwarf2EHNewbiesHowto|DWARF]](GCC 런타임)가 사용된다. 저 기법이 등장하기 이전까지는 SJLJ를 사용하여 예외처리를 구현하였다.]을 사용하기 때문에 예외가 발생하기 전까지는 성능 하락이 발생하지 않는다. {{{if}}}문 처리는 분기 예측에 따라 1~20 cpu cycle를 소모하지만, '''예외 처리는 [[http://ithare.com/infographics-operation-costs-in-cpu-clock-cycles/|5000~10000 cpu cycle를 소모]]한다'''는 점을 알아야 한다. 따라서 예외 처리를 남용해서는 안되며 성능이 중요한 부분에서는 사용하지 않는 것을 권장한다. [[https://docs.microsoft.com/ko-kr/cpp/cpp/errors-and-exception-handling-modern-cpp|#]] 예외는 수많은 프로그래밍 언어의 핵심 오류 매커니즘이다. 하지만 이런 상당한 단점이 있게 되자, 대규모 프로젝트에서는 성능 상의 이유로 예외의 사용을 금지하게 되고[* P0709에 따르면 무려 52%의 프로그래머가 프로젝트 내에서 예외가 금지되었다고 답하였다.]. C++17의 {{{filesystem}}} 라이브러리의 경우 예외 처리와 에러코드용 인터페이스를 혼용해서 제공해버릴 정도로 C++의 예외 처리는 처리 비용이 상당하다. 그러나 RTTI와 달리 C++의 표준 라이브러리를 사용하고 오류 처리를 동반하는 한 예외는 현실적으로 피할 수 없다. C++에서 객체의 생성이나 복사를 실패시킬 수 있는 문법적 기능은 예외가 유일하며 표준 라이브러리는 이를 적극적으로 활용하기 때문이다 [* two-phase construction 등 회피 꼼수가 있으나 어디까지나 꼼수다. C++ 특성상 예외를 완전히 피하면서 깔끔한 코드를 설계하는 것은 매우 어렵다.]. 물론 처리하기 전에 앞서 확인하는 과정을 통해 피할 수 있는 예외는 당연히 피하는 것이 좋다. 예를 들어 {{{std::optional}}}에 유효한 객체를 가지고 있지 않을 때 객체에 접근하여 발생하는 {{{std::bad_optional_access}}} 예외는 접근하기 전에 미리 확인하여 피할 수 있다. 그러나 컨테이너 라이브러리 등을 사용하는 과정에서 {{{std::bad_alloc}}}과 같이 메모리 할당의 실패로 발생하는 예외는 남은 메모리 크기를 확인하더라도 피하지 못할 수 있다. 메이저 컴파일러들 중 일부는 RTTI와 마찬가지로 예외 처리를 끄는 기능을 제공하긴 한다. 하지만 이 경우 표준 라이브러리를 사용하는 중 거기서 예외를 던지는 순간 정의되지 않은 동작(undefined behavior)으로 돌입한다. 컴파일러나 런타임 라이브러리에 따라 다르긴 하지만, 대부분의 경우 프로그램이 종료된다. 다만 C++는 다른 언어들과 다르게 모든 Error Handling을 std::exception으로만 하는 언어가 아니다. C++를 창시한 Bjarne Stroustrup에 따르면 C++는 리턴값, static_assert, assert, std::except, noexcept 등을 이용해 Error Handling을 할 수 있으며, C언어에서 if로 에러 핸들링 하듯이 쓰면 큰일난다! 오히려 예외를 쓰면 실행이 더 빨라지는 경우도 있으니 숙련된 프로그래머는 이를 잘 활용하여 별도의 오버헤드 없이 Error Handling을 할 수 있다. 예외는 C/C++의 [[포인터]]와 같이 양날의 검이니 조심히 사용하도록 하자. 이렇게 성능 상의 문제로 예외 처리를 기피하는 상황이 끊임없이 발생하자, 아예 오류 코드 방식을 확장시킨 {{{Boost.Outcome}}} 혹은 {{{std::expected}}} 등으로 대체하려고 하고 있다. 이러한 개념을 먼저 도입한 언어의 예로 [[Rust(프로그래밍 언어)|Rust]]와 [[Kotlin]]의 {{{Result}}}를 들 수 있다. Rust는 예외 대신 {{{Result}}} 객체와 열거형 [* Rust의 열거형은 C++의 {{{variant}}}다.]을 사용하며, {{{From}}} 트레이트가 구현되어 있는 경우 {{{?}}} 연산자에서 자동 변환을 지원한다. 그 외에 동적 형변환을 포기하고 에러 코드와 예외의 장점을 섞은 표준안이 제안되고 있으므로 [[http://open-std.org/JTC1/SC22/WG21/docs/papers/2019/p0709r4.pdf|#P0709]] 언젠간 개선되리라는 희망을 가질 수는 있겠지만, 아직도 많은 논의가 계속되고 있기 때문에[[https://www.reddit.com/r/cpp/comments/c75ipk/why_stdexpected_is_not_in_the_standard_yet_is_it/|#]] 당분간은 적용이 요원하다.저장 버튼을 클릭하면 당신이 기여한 내용을 CC-BY-NC-SA 2.0 KR으로 배포하고,기여한 문서에 대한 하이퍼링크나 URL을 이용하여 저작자 표시를 하는 것으로 충분하다는 데 동의하는 것입니다.이 동의는 철회할 수 없습니다.캡챠저장미리보기