嵌入式C++需避免STL动态分配、虚函数和异常等隐式开销,改用std::array、CRTP、静态内存池,并严格控制栈空间与编译选项。
嵌入式系统通常没有完整堆管理或禁用 malloc/free,而标准 STL 容器(如 std::vector、std::string)默认在堆上分配内存,运行时可能崩溃或不可预测。
std::array 替代 std::vector
etl 或 folly::small_vector 的裁剪版),并确保其配置为使用静态内存池operator new——需检查编译器链接的 libstdc++/libc++ 是否启用了 -fno-use-cxa-atexit 和自定义 new 操作符虚函数表(vtable)增加 ROM 占用,虚调用引入间接跳转开销,在 Cortex-M0/M3 等无分支预测的小核上延迟明显;且每个含虚函数的类实例额外携带 4 字节 vptr。
Curiously Recurring Template Pattern)实现编译期多态g++ -O2 可能优化掉单实现类的虚调用,但不可依赖)默认 C++ 编译选项常为通用场景优化,嵌入式需主动约束:避免模板爆炸、抑制冗余符号、关闭非必要 ABI 特性。
-fno-exceptions -fno-rtti -fno-threadsafe-statics,防止隐式插入异常处理桩和 guard 变量逻辑__attribute__((optimize("O3,fast-math,no-tree-vectorize")))(注意 fast-math 可能破坏 IEEE 浮点语义)arm-none-eabi-g++ -ffunction-sections -fdata-sections 配合链接脚本 --gc-sections 删除未引用代码/数据sizeof 和 alignof —— 某些 STL 类型(如 std::function)在不同工具链下尺寸差异极大,可能意外撑爆栈嵌入式通常只配几 KB 栈(如 2KB),而 C++ 默认栈行为比 C 更“激进”:临时对象、隐式拷贝、异常栈展开都会快速耗尽空间,且多数 MCU 无栈溢出检测。
arm-none-eabi-gcc -fstack-usage 生成 .su 文件)std::array 直接压栈,等价于裸数组但更易被忽略operator new 和 operator delete 为 panic-on-fail,而非返回 nullptr;同时禁用
extern "C" void* operator new(size_t size) {
while(1); // 或触发 HardFault
}
extern "C" void operator delete(void*) noexcept {}
C++ 在资源受限环境不是不能用,而是每个语法特性都要问一句:它悄悄申请了什么内存?增加了多少指令周期?有没有替代的、更透明的写法?最危险的从来不是写不出功能,而是没意识到某行看似干净的 std::string s = "hello" 正在往只剩 64 字节的栈里塞 24 字节对象加堆分配。