C++ 最佳实践 | 5. 可移植性及多线程
本系列是开源书C++ Best Practises的中文版,全书从工具、代码风格、安全性、可维护性、可移植性、多线程、性能、正确性等角度全面介绍了现代 C++项目的最佳实践。本文是该系列的第五篇。
可移植性
明确使用的类型
大多数产生告警的可移植性问题都是因为我们没有注意类型。标准库和数组使用size_t
作为索引,标准容器的大小使用size_t
类型。如果对 size_t 的处理不正确,可能会潜伏有微妙的 64 位问题,这种问题只有在开始 32 位整型索引溢出之后才会出现。另一种类似问题是char
类型和unsigned char
类型的使用。
参考: http://www.viva64.com/en/a/0010/
使用标准库
std::filesystem
C++17 新增了新的filesystem
库,在所有支持的编译器上提供了可移植的文件系统访问能力。
std::thread
C++11 的线程功能能够基于pthread
或WinThreads
使用。
其他
本系列中的其他大多数问题最终都可以归结到可移植性上,尤其要注意避免静态(static)类型(参考下文多线程部分)。
多线程
避免全局数据
全局数据会导致函数之间意想不到的副作用,并可能使代码难以甚至无法并行化。即使现在的代码不是为了并行化而写,也没有理由在将来永远不做并行化。
静态(static)数据
除了作为全局数据之外,静态数据并不总是像期望的那样被构造和析构,在跨平台环境中尤其如此。例如,有个g++的bug就是关于从动态模块加载的共享静态数据的销毁顺序的。
共享指针
std::shared_ptr
和全局变量一样(http://stackoverflow.com/a/18803611/29975),允许多段代码与相同的数据交互。
单例(Singleton)
单例通常使用静态和/或shared_ptr
实现。
避免堆操作
堆操作在多线程环境中要慢得多,在许多甚至大多数情况下,复制数据会更快,更别提还有move
操作这之类的东西。
互斥对象(mutex)和可变对象(mutable)一起使用(M&M 规则,C++11)
对于成员变量,最好同时使用互斥锁和可变变量,这在两方面都适用:
可变成员变量被假定为共享变量,因此应该与互斥锁同步(或原子化)。
如果一个成员变量本身是互斥的,那么应该是可变的,这是在 const 成员函数中使用它所必需的。
更多信息请参阅 Herb Sutter 的文章: GotW #6a Solution: Const-Correctness, Part 1
也可以参考前面关于const &
返回值安全性的讨论。
你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。
微信公众号:DeepNoMind
版权声明: 本文为 InfoQ 作者【俞凡】的原创文章。
原文链接:【http://xie.infoq.cn/article/270805ef9ceee27e286c126e0】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论