正统 C++ (2016)
摘要
正统C++是C++的一个最小子集,避免使用现代特性,倡导更简单、类似C的风格,以提高可读性和兼容性。
<p><a href="https://lobste.rs/s/fiiamm/orthodox_c_2016">评论</a></p>
查看缓存全文
缓存时间: 2026/06/12 12:53
# 正统 C++ 源文: https://bkaradzic.github.io/posts/orthodoxc++/ **目录**- 什么是正统 C\+\+? (https://bkaradzic.github.io/posts/orthodoxc++/#what-is-orthodox-c) - 为什么不用现代 C\+\+? (https://bkaradzic.github.io/posts/orthodoxc++/#why-not-modern-c) - 为什么要用正统 C\+\+? (https://bkaradzic.github.io/posts/orthodoxc++/#why-use-orthodox-c) - 正统 C\+\+ 的 Hello World (https://bkaradzic.github.io/posts/orthodoxc++/#hello-world-in-orthodox-c) - 应该使用什么? (https://bkaradzic.github.io/posts/orthodoxc++/#what-should-i-use) - 现在可以安全使用现代 C\+\+ 的某些特性了吗? (https://bkaradzic.github.io/posts/orthodoxc++/#is-it-safe-to-use-any-of-modern-cyear-features-yet) - 修订历史 (https://bkaradzic.github.io/posts/orthodoxc++/#revision-history) - 还有其他类似的想法吗? (https://bkaradzic.github.io/posts/orthodoxc++/#any-other-similar-ideas) - 代码示例 (https://bkaradzic.github.io/posts/orthodoxc++/#code-examples) 本文最初作为 gist 发布于此 (https://gist.github.com/bkaradzic/2e39896bc7d8c34e042b)。 ## 什么是正统 C\+\+? 正统 C\+\+(有时被称为 **C\+**)是 C\+\+ 的一个最小子集,它改进了 C,但避免了所谓现代 C\+\+ 中所有不必要的东西。它与现代 C\+\+ (https://stackoverflow.com/questions/3661237/what-is-modern-c) 所应包含的东西完全相反。 ## 为什么不用现代 C\+\+? 早在 1990 年代末,我们也是当时现代 C\+\+ 的潮人,并且使用最新特性。我们告诉所有人他们也应该使用那些特性。随着时间的推移,我们认识到仅仅因为某些语言特性存在就使用它们是不必要的,或者我们使用的某些特性被证明是糟糕的(如 RTTI、异常和流),或者它们因不必要的代码复杂性而适得其反。如果你认为这毫无意义,那就再等几年,你也会讨厌现代 C\+\+ (http://archive.md/2016.05.17-214038/https://www.linkedin.com/pulse/why-i-dont-spend-time-modern-c-anymore-henrique-bucher-phd)(“为什么我不再花时间在现代 C\+\+ 上”存档的 LinkedIn 文章)。 d0pfbigxcaeip0m ## 为什么要用正统 C\+\+? > “在 C\+\+ 内部,有一个更小、更简洁的语言挣扎着想要出来。” –Bjarne Stroustrup (https://web.archive.org/web/20201128151900/https://www.stroustrup.com/quotes.html#:~:text=%22Within%20C++,to%20get%20out%22.) 使用正统 C\+\+ 限制编写的代码库将更易于理解、更简单,并且能够用较旧的编译器构建。用正统 C\+\+ 子集编写的项目更容易被其他 C\+\+ 项目接受,因为正统 C\+\+ 使用的子集不太可能违反采用者的 C\+\+ 子集偏好。 ## 正统 C\+\+ 的 Hello World ``` #include int main() { printf("hello, world\n"); return 0; } ``` ## 应该使用什么? - 类 C 的 C\+\+ 是一个好的起点:如果代码不需要更多复杂性,就不要添加不必要的 C\+\+ 复杂性。通常,代码应该对任何熟悉 C 语言的人可读。 - 不要这样做 (http://archive.md/2014.04.28-125041/http://www.boost.org/doc/libs/1_55_0/libs/geometry/doc/html/geometry/design.html),在正统 C\+\+ 中,“设计原理”的结尾应该紧跟在“非常简单,它是可用的。**EOF**”之后。 - 不要使用异常 (https://web.archive.org/web/20190116034706/http://www.lighterra.com/papers/exceptionsharmful/)。 > 异常处理是唯一需要复杂运行时系统大量支持的 C\+\+ 语言特性,并且它是唯一即使你不使用也有运行时开销的 C\+\+ 特性——有时表现为每个对象构造、析构和 try 块进入/退出处的额外隐藏代码,并且总是通过限制编译器优化器的能力,往往相当显著。然而 C\+\+ 异常规范在编译时并不强制实施,所以你甚至无法知道你没有忘记处理某个错误情况!在风格上,异常风格的错误处理与 C 风格的错误返回码不太契合,这导致了编程风格的真正分裂,因为大量 C\+\+ 代码必须不可避免地调用到底层的 C 库。 - 不要使用 RTTI。 - 不要使用 C 运行时包含文件的 C\+\+ 运行时包装(`<cstdio>`、`<cstdlib>` 等),改用 C 运行时(`<stdio.h>`、`<stdlib.h>` 等)。 - 不要使用流(`<iostream>`、`<sstream>` 等),改用 printf 风格的函数。 - 除非你不关心内存管理,否则不要使用 STL 中任何分配内存的东西。请参阅 CppCon 2015: Andrei Alexandrescu “std::allocator 之于分配就像 std::vector 之于烦恼” (https://www.youtube.com/watch?v=LIb3L4vKZ7U) 的演讲,以及为什么许多 AAA 游戏开发工作室放弃 STL (https://web.archive.org/web/20220227163717/https://threadreaderapp.com/thread/1497768472184430600.html) 的帖子以获取更多信息。 - 不要过度使用元编程进行学术手淫。适度使用,只在必要且能降低代码复杂度的地方使用。 - 警惕当前标准 C\+\+ 中引入的任何特性,最好等到这些特性在下一次标准迭代中得到改进后再使用。例如 C\+\+11 的 `constexpr` 在 C\+\+14 中才变得可用(根据 Jason Turner (http://archive.md/2018.02.01-171248/https://twitter.com/lefticus/status/958931109009440768),cppbestpractices.com 的策展人)。 - 不要使用模块 (https://web.archive.org/web/20251019163438/https://nibblestew.blogspot.com/2025/08/we-need-to-seriously-think-about-what.html)。 > 使用模块会带来以下缺点:1. 需要重写(可能重构)你的代码。2. 失去可移植性。3. 模块二进制文件(除了 MSVC)不可移植,因此你无论如何都需要为库提供头文件。4. 项目构建设置变得更加复杂。5. 除了最新版本之外的任何工具链版本都无法工作(在撰写本文时,Apple 的模块支持被列为“部分”)。作为所有这些的交换,你,普通的开发者,得到以下优点:1. 没有。 ## 现在可以安全使用现代 C\+\+ 的某些特性了吗? 由于编译器、操作系统发行版等对 C\+\+ 标准的采用滞后,通常无法立即开始使用新的有用语言特性。一般准则是:如果当前年份是 C\+\+ *年份*+5,那么可以安全地**有选择地**使用 C\+\+ *年份*的特性。例如,如果标准是 C\+\+11,当前年份 >= 2016,那么可能是安全的。如果编译你的代码所需的标准是 C\+\+17,而年份是 2016,那么显然你在实践“简历驱动开发”方法论。如果你是在开源项目中这样做,那么你创造的不是别人能用的东西。 ## 修订历史 **更新** 截至 2025 年 1 月 14 日,正统 C\+\+ 委员会批准有选择地使用 C\+\+20。 - 2025 年 10 月 19 日 - 添加了关于模块的信息 (https://bkaradzic.github.io/posts/orthodoxc++/#:~:text=Don%E2%80%99t%20use%20modules.,Nothing.)。 - 2019 年 1 月 16 日 - 添加了关于异常处理的信息 (https://bkaradzic.github.io/posts/orthodoxc++/#:~:text=Don%E2%80%99t%20use%20exceptions.,C%20libraries.)。 - 2018 年 2 月 1 日 - 添加了关于 constexpr 需要多次迭代才能变得有用的信息 (https://bkaradzic.github.io/posts/orthodoxc++/#:~:text=Wary%20of%20any,curator)。 - 2016 年 1 月 16 日 - 原始文章。 (https://gist.github.com/bkaradzic/2e39896bc7d8c34e042b/efe7b7470a488d7752ca28c87146d80d83b3e71b)。 ## 还有其他类似的想法吗? - 嵌入式 C\+\+ https://en.wikipedia.org/wiki/Embedded_C%2B%2B - 名义 C\+\+ http://archive.md/2016.08.07-162105/https://namandixit.github.io/blog/nominal-c++/ - 健全的 C\+\+ http://archive.md/2016.08.07-162220/http://flohofwoe.blogspot.nl/2013/06/sane-c.html - 为什么你的 C\+\+ 应该简单 http://archive.md/2017.03.19-055108/https://hacksoflife.blogspot.nl/2017/03/why-your-c-should-be-simple.html - C\+\+,不是你的问题,是我的问题。https://web.archive.org/web/20190227061553/https://c0de517e.blogspot.com/2019/02/c-its-not-you-its-me.html - “保持 C-mple” Alexander Radchenko 悉尼 C\+\+ 聚会 https://www.youtube.com/watch?v=lTXHOOwfTAo - C\+\+ 的一种方言 https://web.archive.org/web/20200521234043/https://satish.net.in/20180302/ - Defold 引擎代码风格 https://web.archive.org/web/20241003193318/https://defold.com/2020/05/31/The-Defold-engine-code-style/ - Orthodoxy - Clang 编译器的插件,有选择地禁用 C\+\+ 语言的特定特性 https://github.com/d-musique/orthodoxy?tab=readme-ov-file#orthodoxy ## 代码示例 - 任何能用 C\+\+ 编译器编译的 C 源代码。 - DOOM 3 BFG https://github.com/id-Software/DOOM-3-BFG - Qt https://github.com/qtproject (当使用 no-rtti、no-exceptions 构建时) - dear imgui https://github.com/ocornut/imgui - bgfx https://github.com/bkaradzic/bgfx - TheForge https://github.com/ConfettiFX/The-Forge - Oryol https://github.com/floooh/oryol - Network Next SDK https://github.com/networknext/sdk **\- 还有一件事...** 我使用 bgfx 的使命是通过提供一个跨平台、图形 API 无关的渲染库来赋能游戏开发者,该库简化了在不同平台上移植游戏的过程,确保无缝的性能和兼容性,而无需引擎锁定。如果你喜欢这篇文章并支持我的使命,请考虑成为赞助者 (https://github.com/sponsors/bkaradzic)! ❤️
相似文章
C语言中在C++中仍然无法工作的构造——以及一些已发生变化的构造
一篇更新经典调查的博文,关于C语言中在C++中无法工作的构造,涵盖了C++20和C23标准中影响兼容性的变化。
新古典C++:分段迭代器再探
重温Matt Austern在2000年关于分段迭代器的论文,该迭代器使分层算法能够利用数据结构分段提升性能,并讨论其在libc++和Boost库中的现代应用。
C++26:标准库强化
C++26 引入了标准化的库强化机制,用于在运行时捕获常见的未定义行为(如越界访问)。基于 Google 的生产经验,此举仅带来 0.30% 的性能开销,同时将段错误减少了 30%。
C++ 标准库在过去十五年间一直在自我撤步,证据公开
一份详细的目录,列出了从 C++11 到 C++26 期间被正式弃用、非正式不推荐或由于 ABI 约束实际上已损坏但无法修复的 C++ 标准库特性。文章指出,C++ 委员会推出一系列替代品来替换其自身特性的模式始终如一,其中包含一个基准测试,显示 Rust 和 C++ 标准库容器之间的 P99 延迟差异高达 58 倍。
关于C扩展、可移植性和替代编译器
本文讨论了编写可移植C代码的实际挑战,这些挑战源于对非标准编译器扩展和glibc条件头文件的依赖,并通过构建C编译器的示例进行说明。