예외 (Exceptions)¶
우리는 C++ 예외를 사용하지 않습니다.
장점:
- 예외를 쓰면 애플리케이션의 상위 계층이, 깊이 중첩된 함수에서 일어난 "일어날 수 없는" 실패를 어떻게 처리할지 결정할 수 있습니다. 알아보기 어렵고 실수하기 쉬운 오류 코드 장부 관리 없이 말입니다.
- 예외는 요즘의 다른 언어 대부분이 사용합니다. C++에서 예외를 쓰면 Python, Java, 그리고 남들이 익숙한 C++과 더 일관성 있게 됩니다.
- 일부 서드파티 C++ 라이브러리가 예외를 사용하므로, 내부적으로 예외를 꺼 두면 그런 라이브러리와 통합하기가 더 어려워집니다.
- 예외는 생성자가 실패를 알릴 수 있는 유일한 방법입니다. 팩토리 함수나
Init()메서드로 이를 흉내 낼 수 있지만, 각각 힙 할당이나 새로운 "무효" 상태를 요구합니다. - 예외는 테스트 프레임워크에서 정말 편리합니다.
단점:
- 기존 함수에
throw문을 추가하면 그 함수를 거쳐 호출하는 모든 함수를 살펴봐야 합니다. 그것들은 최소한 기본적인 예외 안전성을 보장하거나, 아니면 그 예외를 절대 잡지 않고 그 결과로 프로그램이 종료되는 것을 받아들여야 합니다. 예를 들어f()가g()를 호출하고g()가h()를 호출하는데,h가 던진 예외를f가 잡는다면,g는 주의하지 않으면 뒷정리를 제대로 하지 못할 수 있습니다. - 더 일반적으로, 예외는 코드를 보고 프로그램의 제어 흐름을 파악하기 어렵게 만듭니다. 함수가 예상하지 못한 지점에서 반환할 수 있기 때문입니다. 이는 유지보수와 디버깅을 어렵게 합니다. 예외를 어디서 어떻게 쓸 수 있는지에 대한 규칙을 두어 이 비용을 줄일 수는 있지만, 그만큼 개발자가 알고 이해해야 할 것이 늘어납니다.
- 예외 안전성에는 RAII와 그에 맞는 다른 코딩 관행이 모두 필요합니다. 올바른 예외 안전 코드를 쉽게 쓰려면 뒷받침하는 장치가 많이 필요합니다. 게다가 독자가 호출 그래프 전체를 이해하지 않아도 되게 하려면, 예외 안전 코드는 지속되는 상태에 쓰는 로직을 "커밋" 단계로 격리해야 합니다. 여기에는 이득과 비용이 함께 따릅니다(커밋을 격리하려고 코드를 알아보기 어렵게 만들어야 하는 경우도 있습니다). 예외를 허용하면 그럴 값어치가 없을 때조차 그 비용을 항상 치러야 합니다.
- 예외를 켜면 만들어지는 바이너리마다 데이터가 추가되어 컴파일 시간이 (아마 조금) 늘고 주소 공간 압박이 커질 수 있습니다.
- 예외를 쓸 수 있다는 사실 자체가, 개발자가 적절하지 않은 곳에서 예외를 던지거나 안전하지 않은데도 예외로부터 복구하려 들도록 부추길 수 있습니다. 예를 들어 잘못된 사용자 입력 때문에 예외가 던져져서는 안 됩니다. 그런 제약들을 문서화하려면 이 스타일 가이드를 더 길게 만들어야 할 것입니다!
결정:
겉으로만 보면 예외를 쓰는 이득이 비용보다 크며, 새 프로젝트에서는 특히 그렇습니다. 하지만 기존 코드에서는 예외를 도입하는 것이 그에 의존하는 모든 코드에 영향을 미칩니다. 예외가 새 프로젝트 바깥으로 전파될 수 있다면, 그 새 프로젝트를 기존의 예외 없는 코드에 통합하는 것도 문제가 됩니다. Google에 있는 기존 C++ 코드 대부분이 예외를 다룰 준비가 되어 있지 않기 때문에, 예외를 발생시키는 새 코드를 받아들이기가 상대적으로 어렵습니다.
Google의 기존 코드가 예외를 견디지 못한다는 점을 감안하면, 예외를 쓰는 비용은 새 프로젝트에서의 비용보다 다소 큽니다. 전환 과정은 느리고 실수하기 쉬울 것입니다. 우리는 오류 코드나 어서션 같은, 예외를 대신할 수 있는 방법들이 큰 부담을 준다고 보지 않습니다.
예외를 쓰지 말라는 우리의 권고는 철학적이거나 도덕적인 근거가 아니라 실용적인 근거에서 나온 것입니다. 우리는 Google에서 우리의 오픈소스 프로젝트를 쓰고 싶은데 그 프로젝트들이 예외를 쓰면 그러기가 어렵기 때문에, Google 오픈소스 프로젝트에서도 예외를 쓰지 말라고 권고해야 합니다. 처음부터 전부 다시 한다면 아마 상황이 달랐을 것입니다.
이 금지는 std::exception_ptr, std::nested_exception 같은 예외 처리 관련 기능에도 적용됩니다.
Windows 코드에는 이 규칙의 예외가 있습니다(말장난 의도는 없습니다).
옮긴이 풀이¶
핵심: Google C++ 코드에서는 예외를 쓰지 않는다¶
이 결정은 철학이 아니라 실용적 이유에 근거합니다. Google의 기존 C++ 코드 대부분이 예외를 처리할 준비가 되어 있지 않아, 예외를 던지는 새 코드를 섞으면 모든 의존 코드에 영향을 주고 통합이 어려워집니다.
왜 (이론적 장점에도 불구하고) 막는가?¶
- 새 함수에
throw를 넣으면 그 함수를 거쳐 호출하는 모든 함수가 최소한의 예외 안전성을 보장해야 합니다. - 예외는 제어 흐름을 보이지 않게 만들어(예상치 못한 지점에서 반환) 유지보수·디버깅을 어렵게 합니다.
- 예외 안전 코드는 RAII와 "커밋 단계 격리" 같은 추가 장치를 요구하며, 그 비용은 예외를 안 쓰는 코드도 늘 떠안게 됩니다.
범위와 예외¶
std::exception_ptr,std::nested_exception같은 예외 관련 기능도 금지에 포함됩니다.- 새 프로젝트만 놓고 보면 장점이 더 클 수 있지만, 기존 코드베이스와의 호환성 때문에 일관되게 금지합니다.
- 단, Windows 코드에는 이 규칙의 예외가 있습니다.