1. 개요
C++의 평가를 정리한 문서2. 평가
2.1. 장점
2.1.1. 무비용 추상화
C++은 시스템 프로그래밍 언어이기 때문에 zero-cost abstraction, 즉 "네가 쓰지 않는 것에 대해서는 성능 하락을 주지 않는다"라는 것을 언어의 설계 철학으로 하고 있다. 또한, 런타임 성능을 쥐어짜내기 위해 인라이닝, 컴파일 타임 프로그래밍 관련 수많은 기능을 도입한 언어이기 때문에 빠르게 동작하는 코드를 짤 수 있다. 벤치마크 결과[1]2.1.2. 많은 시스템에서 지원하는 언어
다른 언어에 밀려 점유율이 조금씩 줄어들고는 있지만, 오래전부터 사용되어왔기 때문에 많은 시스템에서 지원하며, C++로 계속 유지되고 있는 프로젝트가 많다. TIOBE에는 2024년 12월 기준 2위를 차지하고 있다. PYPL의 경우 2024년 12월 기준 4위를 차지하고 있다.“... 나는 꼭 '보이지 않는'이란 수식어를 붙이는데, 이것은 매우 빈번하게 C++가 가장 아래쪽의 인프라를 구성하는 요소로 존재하기 때문이다. 우리는 C++를 매우 다양한 방식으로 지금 현재 이용하고 있지만, C++가 눈에 직접 보이진 않는다. 어쩌면 'C++ inside'로고를 오래전에 개발했더라면 좋았을 것같다. intel inside라는 인텔의 마케팅 로고를 패러디하고 있는 듯. 우리는 (C++를) 보지 못하고 있다. 우리는 전화통신을 사용하지만 C++를 보지 못하고 있다. 우리는 카메라를 사용하지만 C++를 보지 못하고 있다. 우리는 OS를 사용하지만 C++를 보지 못하고 있다. 우리는 시그널 프로세싱을 사용하지만 C++를 보지 못하고 있다. 우리는 C++를 안 보려고 하는 경향이 있다. 하지만 C++는 매우 빈번하게 모든 것의 하부에 (설령 그것이 Java, C#, Python등 다른 언어로 작성된 것이라고 하더라도) 존재하고 있다.”
- Bjarne Stroustrup Core C++ 2021 :: Bjarne Stroustrup :: Thriving in a crowded and changing world: C++ 2006-2020 [2]
비아르네 스트로우스트루프에 따르면 C++20에 도달한 지금의 C++를 한 마디로 요약하면, “An invisible foundation of "everything"(모든 것의 보이지 않는 기반)”이라고 한다. C++가 드라이버와 같은 시스템의 핵심 구성 요소를 작성하고 유지하는데 사용됨으로써 보이지는 않지만 분명히 존재한다는 것이다.- Bjarne Stroustrup Core C++ 2021 :: Bjarne Stroustrup :: Thriving in a crowded and changing world: C++ 2006-2020 [2]
2.1.3. 수많은 기능
C++은 절차적, 객체지향, 일반화 프로그래밍 등 프로그래밍 언어에서 제공할 수 있는 대다수 패러다임을 지원하는 언어이다. 같이 비교되는 C의 경우 객체지향이나 일반화 프로그래밍을 언어 차원에서 지원하지 않기 때문에 이를 흉내내려면 알아보기도 힘든 매크로 떡칠을 동원해야 하는데, 이를 언어 차원에서 성능 하락 없이 쓸 수 있다는 건 C에 비해 엄청난 메리트라고 할 수 있다. 성능에 목숨을 걸면서 프로그램의 복잡도가 높아지는 텐서플로, 파이토치, 행렬 라이브러리, 금융권의 트레이딩 시스템 등은 전부 C 대신 C++을 사용하는데, 이것이 괜히 그런 것이 아니다.2.2. 단점
2.2.1. 높은 학습 난이도
[3][4]
C++11이 발표된 2011년을 기점으로 매 3년마다 개정된 표준을 발표하는 것이 관례화 되면서, 점차 추가되어가는 표준 라이브러리 기능과 문법들을 사용한 코드를 보면 도저히 C언어 기반 언어라고는 생각이 들지 않을 정도로 차이가 상당히 커지고 있다. 그러나 기능이 추가되고 성능이 개선되었지만 그만큼 배워야 할 것은 더욱 늘어나게 되었다. 현재 기능의 방대함은 타의 추종을 불허하기 때문에, 모든 요소를 이해하겠다는 생각은 애초부터 버리는게 좋다. C++로 실무 업무를 보는 개발자들도 절대로 요소 전부를 가져다 쓰지 않고 필요한 부분만 참고해가며 사용한다. 특히 C++11 이후 핵심 요소 중 하나인 우측값 참조는 이해하기 어렵다.
큰 문제는 기능은 너무 많은데 그 중 실제로 잘 배울 필요가 있는 기능은 그렇게 많진 않고, 나머지는 라이브러리 제작자가 아닌 이상 배울 필요가 없는 기능과, 쓰면 오히려 독이 되는 (주로 오래된 레가시 C++ 코드와의 호환성 때문에 억지로 표준에 유지시켜 놓은) 기능들이다. 너무 오래되고, C와 섞인 저질 학습 자료들이 지나치게 많기 때문에 초보자 입장에서는 어떤 것이 좋은 습관이고 어떤 것이 좋지 않은 습관인지 익히는 것이 어렵다.
C++을 배우려는 초보자가 인터넷에 문의를 해보면 보통 초보자용 1개, 중급자용 1개, 표준 라이브러리 서적 1개 등등등 해서 여러 개 읽으라는 답변들이 많이 달리며, 개중에는 1000쪽이 넘어가는 책들도 있다.[5] 물론 반드시 1000쪽짜리 책으로 공부해야 한다는 건 아니지만 C++ 교재들은 대체로 다른 언어 교재에 비해 두꺼운 편이다. 모던 C++의 새로운 기능을 배우고 싶다면 이들을 자세히 구글링하여 찾고 부족한 내용은 C++ 표준 라이브러리를 정리한 사이트에서 알아보는 것이, 최신의 C++ 기능들을 가장 빠르게 익힐 수 있는 방법이다. 일일이 검색하는 것이 어렵거나 귀찮을 경우 ChatGPT와 같은 생성형 인공지능에게 질문을 직접 해 설명을 듣는 방법을 이용해도 좋다.
2.2.2. 메모리 관리 & 보안
C++는 C언어와 마찬가지로 메모리 관리가 비교적 자유로워서 직접 최적화가 가능한 부분이 많지만 실수하기 쉽고 설계가 어렵다는 단점이 있다. 다른 프로그래밍 언어와 구별되는 가장 큰 차이점이다.프로그래머들의 평균적인 기량이 뛰어나더라도 사람은 가끔이라도 반드시 실수를 하게 되므로 버그가 발생할 수 있다. 특히 포인터와 참조자와 할당된 메모리 사이에 존재할 수 있는 복잡한 관계를 간과할 수 있는데, 사소해보이는 실수라 할지라도 이미 해제된 메모리 영역에 접근하도록 허용하여 제어 흐름이 탈취될 수 있다. 그래서 이는 단순 메모리 누수와는 다른 그 이상의 보안상 심각한 문제이다.[6] GC 언어처럼 잘못된 참조자가 존재할 수 없도록 가비지 컬렉터가 알아서 처리해주거나, Rust처럼 언어 차원에서 컴파일 시간에 메모리 소유권을 검사하고 강제하는 기능이 없기 때문에, 이 부분은 C/C++으로 개발할 때 언제나 염두에 둬야 하는 폭탄 같은 위험성이라고 볼 수 있다. 최근 미국의 NSA에서도 차기 프로젝트에는 C++ 대신 GC 언어나 Rust를 쓰라고 권장했을 정도이며, 보안의 중요성이 나날히 높아지는 이 순간 C++의 존속까지 위협하는, 가장 큰 역린이라고 할 수 있다. JDNet 가이드라인
스마트 포인터를 강제한다 하더라도 잘못된 참조자로 인한 보안 문제는 피할 수 없다. 그래서 이러한 문제에 대해 지속적으로 논의가 이루어지며 아얘 Rust처럼 컴파일러가 참조자를 검증할 수 있도록 C++ Lifetime Profile이란 제안서가 발간되기도 했다. 메모리 임의 참조를 막아야 한다,
nullptr
을 아예 불허해야 한다는 프레젠테이션도 C++Con에서 발표된 적이 있다. C++ 개혁 C++ 메모리 안전2.2.3. 애매한 위치
리눅스 진영의 주축인 리누스 토르발스가 메일링 리스트를 통해 언급한 2007년도 비판이 자주 인용된다. 리누스 토르발스에 의하면 C++는 어중간한 지점에 위치한 언어이며 운영체제 개발에 있어 아무런 도움이 되지 않았다고 언급했다. 실제로 C++로 리눅스를 재작성하려고 했다가 다시 되돌린 적이 있다. 프로토타이핑 용도나 단순한 GUI 프로그래밍 용도로 사용하기에는 C++가 일을 충분히 쉽게 하도록 도와주는 친절한 언어가 아니고, 반대로 단순하고 직접적인 구조의 프로그래밍을 장려하는 C언어처럼 날씬한 운영체제 프로그래밍용 언어도 아니라는 것이다.#리누스 토르발스의 발언을 인용한 C++ 비판에 대한 비아르네 스트로우스트루프의 가장 최신 반응은 '그것은 기껏해야 고대의 C++에 대한 비판일 뿐 모던 C++에 적용되는 얘기가 아님.'[7]으로 요약할 수 있다.
"... 사람들은 매우 자주 C++를 잘못 묘사하곤 한다. 사람들은 1984년 근처의 C++를 바라보고 비판을 하곤 하거나, 25년 전[8]의 비판을 발굴해내서 무슨 복음말씀처럼 여기곤 한다. 심지어 나는 오늘 아침에도 리누스가 1990년대 초에 C++에 대해 언급한 코멘트를 레퍼런스로 하는 것을 보았다. 그 당시의 g++ 컴파일러라면 나도 싫다. 하지만 그건 수십년 전이고, 세상은 25년 전과는 많이 달라졌다."
In fact, in Linux we did try C++ once already, back in 1992.
사실 1992년에 이미 리눅스에 C++를 사용하는 것을 시도해보았다.
It sucks. Trust me - writing kernel code in C++ is a BLOODY STUPID IDEA.
구리더라. 커널을 C++로 짜는 것은 정말 개 멍청한 생각이다.
The fact is, C++ compilers are not trustworthy. They were even worse in 1992, but some fundamental facts haven’t changed:
사실 C++ 컴파일러는 신뢰할 만한 것이 못 된다. 1992년에는 더 심각했지만 몇몇 핵심적인 사실은 변하지 않았다:
the whole C++ exception handling thing is fundamentally broken. It’s especially broken for kernels.
C++ 예외 처리는 그냥 처음부터 글러먹었다. 특히 커널을 위해서는 더 그렇다.
2004년 리누스 토발즈의 C++ 평가 #
그러나 비아르네 스트로우스트루프의 평과와 달리 리누스 토발즈는 1990년대를 시작으로 2000년대와 2020년대 까지 꾸준하게 C++를 비난하고 리눅스 커널에 C++ 도입을 반대했다. 정작 역사가 더 짧은 Rust 도입은 찬성#한걸 생각하면 여전히 C++의 문제점이 해결되지 않아 신뢰하지 않음을 알수있다.사실 1992년에 이미 리눅스에 C++를 사용하는 것을 시도해보았다.
It sucks. Trust me - writing kernel code in C++ is a BLOODY STUPID IDEA.
구리더라. 커널을 C++로 짜는 것은 정말 개 멍청한 생각이다.
The fact is, C++ compilers are not trustworthy. They were even worse in 1992, but some fundamental facts haven’t changed:
사실 C++ 컴파일러는 신뢰할 만한 것이 못 된다. 1992년에는 더 심각했지만 몇몇 핵심적인 사실은 변하지 않았다:
the whole C++ exception handling thing is fundamentally broken. It’s especially broken for kernels.
C++ 예외 처리는 그냥 처음부터 글러먹었다. 특히 커널을 위해서는 더 그렇다.
2004년 리누스 토발즈의 C++ 평가 #
실제로 C++20 이후 코루틴과 모듈 및 컨셉트와 같은 기능이 표준안에 추가되면서 아예 다른 언어처럼 보일 정도로 많이 바뀌고 개선되었다. 다만, 2023년 11월 기준 이를 지원하는 라이브러리나 사용하는 프로젝트가 다른 언어들에 비해 거의 없고 활성화되지도 않은 데다 C++를 사용하는 기업들은 안정적이고 오래된 표준안을 선호하므로, 새로운 C++ 문법과 기능을 실무에서 사용하게 되기까지 많은 시간이 걸릴 것이다.
2.2.3.1. C언어와의 호환성
C언어와 호환된다는 특징은 그 자체로 장점과 단점을 모두 갖게 된다. 장점은 높은 호환성과 더불어 C언어 프로젝트와 섞어서 사용하기 쉽다는 것이고 단점은 C언어에 문법을 추가하다보니 C언어의 단점을 그대로 가져오게 되며 다른 언어에 비해 비교적 깔끔하지 못하다는 것이다.C언어의 단점에 대한 대표적인 예로는 매크로가 있는데, C/C++의 매크로는 문자열을 단순 치환하기 때문에 코드 문맥이나 흐름에 따라 디버그하기도 어려운 난해한 문제를 발생시키는 경우가 많다. 초보자들에게 매크로를 함부로 쓰지 말라는 이유가 바로 이 때문이다. #
다만 C언어와 호환된다고만 했지 섞어 쓰는 것은 권장되지 않는다. 오히려 두 언어가 섞이면 관리가 힘들어지고 버그나 예상하지 못한 결과가 나올 수도 있다. C와 C++는 완전히 다른 별개의 언어이며, 웬만하면 섞어 쓰지 말자. [9]
C언어의
#include
문은 다른 언어의 using
, import
, package
와는 결이 다르다. 지정한 파일의 내용을 가감없이 그대로 포함시키는 구문이다. 그 안에 있는 모든 게 상호작용되고 특히 단순 치환하는 매크로 때문에 코드 간 의존성이 발생하여 미리 컴파일할 수 없으며 해당하는 헤더 파일을 컴파일 할 때마다 일일이 포함해야 한다. 원치 않으면 헤더와 소스 파일을 분리해야 한다. 헤더 참조 구조가 중복정의로 복잡해지는 건 덤. 그 결과 C/C++는 컴파일이 가장 느린 언어가 되어버렸다. 이러한 문제를 해결하기 위해 C++20부터 모듈 개념이 도입되었다 [10]. 다른 언어의 패키지, 모듈처럼 C++20의 모듈도 외부와 단절되어 있고 오직 가져오기 구문으로만 참조할 수 있다. 그러므로 이러한 단점은 시간이 지남에 따라 어느 정도 극복될 것이다.그런데 다른 모듈에서 정의된 매크로는 사용하지 못하기 때문에, 매크로로 떡칠된 코드는 다 뜯어 고쳐야 할 수도 있다. 그래서 수많은 기존 프로젝트는 여전히 헤더를 사용할 것으로 보이며, C와의 호환성을 위해서 헤더 참조 구조는 표준에서 없어지지 않을 것이다. 또한 모듈을 모든 C++ 컴파일러에서 지원하는게 아닐 뿐더러, 모듈을 지원하거나 사용하는 라이브러리가 아직은 전무하다. 아니면 이 상황에서 MSVC, GCC, Clang, ICC와 같은 메이저 컴파일러들은 헤더를 프리 컴파일하고 사용하는 확장 기능들을 제공하고 있으므로 이를 사용하는 것이 최선이다.
2.2.3.2. 템플릿의 난해성
상대적으로 느슨한 언어 설계에 의해 SFINAE와 같은 사실상 꼼수에 가까운 기법들이 사용되고 그 중 템플릿 메타 프로그래밍 또한 이에 포함된다. 여기서 말하는 메타 프로그래밍은 컴파일 타임에 실행되는 프로그램이라는 넓은 의미를 가진다. 템플릿은 원래 일반화 프로그래밍을 위해 등장했으나, 템플릿 타입 체크 등의 몇 가지 케이스들을 보완하기 위해 여러 기능들이 추가되기 시작했다. 이러한 기능들은 SFINAE[11]와 같은 트릭에 사용되다가, 어느 때부터 C++ 템플릿을 활용하여 튜링 완전한 메타 언어로써 연산을 컴파일 타임에 수행할 수 있음을 발견했다. 이러한 흐름에서 등장한 템플릿 메타 프로그래밍은 C++의 강력한 기능 중 하나가 되었지만 원론적으로는 언어 표준 명세에서 지원하지 않았다. 문법 관계가 복잡하고 직관적이지 않아 이해하기가 어렵고 컴파일도 오래 걸리며 부자연스럽다거나 난해하다는 의견이 적지 않다. [12]개발자들이 C++에서 손꼽는 어려운 특징 중 하나이다. # # SFINAE가 수행했던 타입 체크는 C++20에서 Concept를 도입하여 템플릿에 명시적 조건을 추가할 수 있게 됨으로써 의미가 없게 되었다.[13]
2.2.4. 성능 저하 요소
C++의 고성능에 대한 철학은 흔히 "don't pay for what you don't use", 즉 성능에 군더더기 없는 기능으로 대표된다. 하지만 두 가지 언어 요소가 이를 정면으로 어기는 기능으로 여겨지는데, 하나는 RTTI(Run-Time Type Information)이고, 다른 하나가 바로 예외(Exception) 이다.2.2.4.1. RTTI
RTTI(Run-Time Type Information)는 컴파일 타임이 아니라 런타임에 객체의 타입이 결정되는 C++의 매커니즘이다. 프로그램이 실행될 때, 객체에 대한 정보를 저장하고 확인해야 하기 때문에 오버헤드가 발생한다. 다음 기능이 대표적인 예이다.dynamic_cast
virtual
dynamic_cast
의 경우 상속 트리 전체를 휘젓고 다녀야 한다는 점 역시 큰 성능 문제로 꼽힌다. 하지만 이에 의존하는 언어의 기능이 거의 없기 때문에 대부분의 상황에서 성능 패널티를 피할 수 있다. 메이저 컴파일러에서 아예 기능을 제외하는 옵션을 제공하는 건 덤이다.virtual
의 경우 50% 정도의 성능 하락이 있을 수 있지만, 현대 컴퓨터에서는 분기 예측을 통해 평균 5~10% 정도의 성능 하락을 보여준다. 그리고 이러한 성능 하락은 어디까지나 함수 호출 비용으로만 계산한 것이기 때문에 특수한 상황이 아니라면 고민하지 않아도 된다. 많은 소프트웨어가 이 문법을 자주 사용한다.[14]현재 RTTI는 유행이 많이 지난 기능이며, 최신 C++ 프로그래밍에서는 잘 사용하지 않는다. 동적 타이핑은 꼭 필요할 때만 사용하는 것이 대세이며, 이외에는 다형성을 구현하기 위해서는 CRTP + type erasure 등의 기법을 주로 사용하며, 이는 성능 패널티가 없다.
2.2.4.2. 예외
예외도 마찬가지로, 설계상 예외 핸들러를 찾기 위해 (RTTI와 동일한 맥락으로) 던져지는 예외의 유형별로 형변환을 해야 하기 때문에 런타임 타입 정보가 필요하다. 따라서 예외를 던질 때마다 적지 않은 성능 패널티가 부과된다. 심지어 예전에는try
블럭을 설치하는 것과, 소멸자가 있는 클래스를 정의하는 것만으로도 프로그램 성능이 크게 하락했었다. 최신 컴파일러는 zero-cost exception[15]을 사용하기 때문에 예외가 발생하기 전까지는 성능 하락이 발생하지 않는다. if
문 처리는 분기 예측에 따라 1~20 cpu cycle를 소모하지만, 예외 처리는 5000~10000 cpu cycle를 소모한다는 점을 알아야 한다. 따라서 예외 처리를 남용해서는 안되며 성능이 중요한 부분에서는 사용하지 않는 것을 권장한다. #예외는 수많은 프로그래밍 언어의 핵심 오류 매커니즘이다. 하지만 이런 상당한 단점이 있게 되자, 대규모 프로젝트에서는 성능 상의 이유로 예외의 사용을 금지하게 되고[16]. C++17의
filesystem
라이브러리의 경우 예외 처리와 에러코드용 인터페이스를 혼용해서 제공해버릴 정도로 C++의 예외 처리는 처리 비용이 상당하다. RTTI와 달리 C++의 표준 라이브러리를 사용하고 오류 처리를 동반하는 한 예외는 현실적으로 피할 수 없다. C++에서 객체의 생성자를 실패시킬 수 있는 문법적 기능은 예외가 유일하며 표준 라이브러리는 이를 적극적으로 활용하기 때문이다 [17]. 물론 처리하기 전에 앞서 확인하는 과정을 통해 피할 수 있는 예외는 당연히 피하는 것이 좋다. 예를 들어
std::optional
에 유효한 객체를 가지고 있지 않을 때 객체에 접근하여 발생하는 std::bad_optional_access
예외는 접근하기 전에 미리 확인하여 피할 수 있다. 그러나 컨테이너 라이브러리, new 등을 사용하는 과정에서 발생하는 std::bad_alloc
과 같이 메모리 할당의 실패로 발생하는 예외는 남은 메모리 크기를 확인하더라도 피하지 못할 수 있다.[18]메이저 컴파일러들 중 일부는 RTTI와 마찬가지로 예외 처리를 끄는 기능을 제공하긴 한다. 하지만 이 경우 표준 라이브러리를 사용하는 중 거기서 예외를 던지는 순간 정의되지 않은 동작(undefined behavior)으로 돌입한다. 컴파일러나 런타임 라이브러리에 따라 다르긴 하지만, 대부분의 경우 프로그램이 종료된다.
이렇게 성능 상의 문제로 예외 처리를 기피하는 상황이 끊임없이 발생하자, 아예 오류 코드 방식을 확장시킨
Boost.Outcome
혹은 <expected>
등으로 대체하려고 하고 있다. 이러한 개념을 먼저 도입한 언어의 예로 Rust와 Kotlin의 Result
를 들 수 있다. Rust는 예외 대신 Result<T, E>
객체와 열거형 [19]을 사용하며, From
트레이트가 구현되어 있는 경우 ?
연산자에서 자동 변환을 지원한다. 그 외에 동적 형변환을 포기하고 에러 코드와 예외의 장점을 섞은 표준안이 제안되고 있으나 갈 길이 멀다. #2.2.5. 패키지 관리자
Rust와 비교했을 때 메모리 안전성 외에 가지게 되는 또다른 상대적인 단점인데, 러스트는 Cargo라는 성능 좋은 패키지 관리자가 공식 지원되는 데 반해 공식적인 패키지 매니저가 없다. 다만 공식적인 패키지 관리자가 없다 뿐이지 무료로 사용 가능한 여러 패키지 관리자가 나와 있는데, 사람들이 가장 많이 쓰는 건 마이크로소프트에서 만든 vcpkg이고, 그 다음으로 많이 쓰이는 건 Conan이다. Conan은 특이하게도 스크립트로 Python을 사용한다.Conan의 로고 이미지 |
진짜 문제는 이들이 Java의 Gradle 또는 Maven, Python의 pip, Node.js의 npm 등 정도의 인지도를 가지고 있지 않다는 것.
[1] 다만 해당 벤치마크의 코드는 언어의 성능을 보여주지 못한다. 그 예시로
fannkuch-redux
테스트에서 C++는 수동 최적화한 SIMD를 사용하고 있지만 C코드는 순수 스칼라에 컴파일러 Auto-vectorization에만 의존한 상태로 연산하고 있기 때문이다. 그 반면에 C코드가 더 빠른 spectral-norm
코드의 경우 C++는 AVX128, C는 AVX256를 사용하고 있고 그에 따라 두배의 스루풋을 보여주고 있기 때문에 순수하게 1:1 언어적 특성에서 보이는 성능 향상을 보여주고 있지 못하다. Java는 JVM이라는 ISA Neutural 한 환경이므로 수동 어셈블리 최적화 같은 하드웨어 가속을 사용하는것이 불가능한데다 애초에 해당 벤치마크 목록들에서 언급하고 있는것이 "These are only the fastest programs. If it's manually vectorized SIMD, does the host language matter?" - 라고 수동 SIMD최적화를 한다면 호스트 언어가 의미가 있는가 라고도 언급하고 있기도 하다. 또한 C++의 경우 클래스와 템플릿을 사용하고 이를 C에서 비슷하게 구현하는 경우 대체로 Context기반의 프로그램 모델을 사용하는데 단순히 class new
와 malloc(struct) + member
만으로 비교해도 C++런타임에서 다루는 추가적인 오버헤드가 없어 C의 성능이 더 잘 나오게 된다.[2] 1:11:14부터 해당 발언 시작[3] 35040분 = 584시간 = 24일 8시간[4] 해당 짤에서 나오는 썸네일을 쓰는 실제 유튜브 영상은 사실 1시간 짜리지만, 별개로 31시간 짜리 영상이 있긴 하다.[5] Bjarne Stroustrup이 직접 쓴 TC++PL이 1,300쪽이다. 물론 이 책은 레퍼런스용 책이기 때문에 TC++PL의 서문에는 아예 'C++를 시작하는 입문자에겐 이 책을 권장하지 않는다'는 말이 적혀 있다.[6] IT 업계에서 최고 수준의 시니어 프로그래머들을 많이 보유하고 있는 구글조차도 웹브라우저 엔진인 블링크의 메모리 접근 위반과 관련한 보안 취약점이 해마다 수십 건씩 계속 발견되고 있다. 모질라도 결국 이러한 문제를 장기적으로 해결하기 위해 차세대 엔진인 서보를 후술할 Rust로 작성할 정도이다.[7] Core C++ 2021 :: Bjarne Stroustrup :: Thriving in a crowded and changing world: C++ 2006-2020(1:12:36부터 해당 발언 시작)[8] 1990년대 중반[9] Jens Gustedt, Modern C[10] MSVC에서는 #include
전처리기 구문을 사용하더라도 모듈로써 동작하도록 설정할 수 있다.[11] Substitution Failure Is Not An Error. 조건에 맞지 않는 템플릿 인자가 들어오면 그 템플릿을 실체화시키지 않는다는 트릭.[12] 이 부분을 언어의 설계 단점으로 보긴 어려운데, 애초에 TMP 은 C++ 에서 공식적으로 지원하는 개념이 아니기 때문이다. 예로 들자면 한 회사(C++)에서 와플 기계(템플릿)를 출시했는데, 사람들이 와플 말고도 여러가지 재료를 넣어서 다른 결과물(TMP)을 만들 수 있는 방법을 찾았다고 하자. 그런데 와플 기계에 부적합한 재료를 넣어 결과물이 타거나 맛 없어 진다고 해도 이 때문에 와플 기계를 개발한 회사를 비판한다는 것은 자연스럽지 않다.[13] 대부분 프로그래머에겐 의미가 없지만, 컴파일러 제작자에게는 의미가 있다. Concept의 구현은 SFINAE 기반이기 때문이다[14] dynamic polymorphism을 원한다면, 쓰기 싫어도 무조건 쓸 수 밖에 없다.[15] 예외를 던지지 않는 실행경로에서는 아무 것도 하지 않아도 되도록 만드는 기법. 요약하면 컴파일러가 전역 예외 핸들러 테이블을 미리 만들어두어, 예외를 던지면 런타임에 해당 테이블을 참조하여 처리하는 방법이다. 이를 구현한 방법은 주로 SEH(MSVC 런타임)와 DWARF(GCC 런타임)가 사용된다. 저 기법이 등장하기 이전까지는 SJLJ를 사용하여 예외처리를 구현했다.[16] P0709에 따르면 무려 52%의 프로그래머가 프로젝트 내에서 예외가 금지되었다고 답했다.[17] two-phase construction 등 회피 꼼수가 있으나 어디까지나 꼼수다. C++ 특성상 예외를 완전히 피하면서 깔끔한 코드를 설계하는 것은 매우 어렵다.[18] std::set_new_handler
함수를 사용하여 메모리 할당 실패 시 호출되는 핸들러를 변경하여 예외 대신 nullptr로 반환하도록 만들 수 있다.[19] Rust의 열거형은 C++의 <variant>
다.