一种更简单的编程风格
在实际项目中,使用 C++ 编程体验相当糟糕,超长的编译时间容易打断心流,复杂的语法也带来沉重的心智负担,而且模板语法几乎不可读也难以调试,特别是 STL 标准库。因此几乎每次我都会将 C++ 项目用 C 重写,简洁的语法和超快的编译速度对比 C++ 真的会让自己解放。但是,C 语言虽然简洁高效,但并非完美,由于历史原因等,某些方面其实也是相当糟糕。
在每次纠结与重写中,我逐渐意识到,也许让 C++ 编译器编译 C 是个不错的选择,我可以稍微使用一些我想要的特性改善编程体验,不过,实际开发中,由于 C++ 的特性过多,每次都忍不住使用一点 C++ 特性,最终项目依然 滑坡 为 C++ 项目,因为我意识到自己需要明确定义一个 C++ 子集规范自己,并审视自己是否真的需要这个特性。
C 与 C++ 的平衡
我总结了一些针对我个人 C 开发的痛点,使用的少量语言级特性来改善开发体验。
可以使用的特性
这些特性几乎不增加编译时间,也不会带来心智负担,但能直接增强开发体验。
namespace: 可以避免符号冲突。
函数重载和默认参数: 可以有效减少冗余,提高可读性。
enum class: 类型安全枚举,也防止命名污染。
constexpr 和 consteval: 几乎可以代替大部分宏函数和常量,类型安全,且可调试,但无法代替元编程和减少代码重复的宏。
lambda: 一次性局部回调。
auto: 类型推导。
谨慎使用的特性
这些特性有用,但可能增加复杂度或编译时间。
简单模板: 解决 C 中没有泛型的问题,仅此而已。
运算符重载: 由于会产生隐式行为,只在数学计算时使用。
属性: 给编译器一些信息,有利于可控性,但一般在最终优化时使用。
禁用的特性
这些特性是复杂度和编译时间的主要来源。
异常和RTTI: 运行时类型信息,增加了编译时间和可执行文件大小,异常我会显式处理。
STL: 复杂度和编译时间的主要来源,隐式行为过多,且难以调试。
智能指针和引用: 不需要,手动管理内存,且使用 C 中的指针。
虚函数和继承: 我个人不使用面向对象编程。
模板元编程: 复杂度和编译时间的主要来源,严重增加心智负担,且难以调试。
使用指南
使用 clang-tidy 等工具进行限制,对于异常和 RTTI,直接在相关编译选项中关闭即可,如 gcc 中的 -fno-exceptions, -fno-rtti。
平时使用 C 风格编程,只使用确定使用的特性,绝不用禁用的特性,可以有效避免代码滑坡。
这种风格的编程能在我保持底层控制力的基础上改善一些自己的编程体验,且有接近 C 的编译速度,保证简洁性和可调试性。
使用 DOD 而不是 OOP 编程
OOP 面向对象编程的核心是把程序组织成一个个对象,对象包含属性和方法,且可以进行封装、继承、多态。
DOD 数据导向设计关注数据如何布局,让 CPU 能高效读取,缓存友好,减少内存跳跃,批量处理同类型数据,并行计算。