C++ 标准库の使用迷思

梦里梦外; 2023-01-01 11:56 203阅读 0赞

转眼 2020 已经过去,回顾来看总有些迷幻,新年之际,自己倒不打算写些什么年终总结,想想还是记一小篇技术小文: C++ 标准库的使用迷思.

了解 C++ 的朋友对于标准模板库肯定不陌生,平日用 C++ 开发时基本也是离不开标准模板库的,举个最普遍的例子:当我们需要动态数组时,甚至于仅需要静态数组时,我们都会第一个想到 vector :

  1. #include <vector>
  2. std::vector<int> int_array;

原因就在于使用 vector 方便且稳定,不用自己处理数组扩容等问题,久而久之,我们总会产生个固有印象:使用 C++ 开发离不开 STL(Standard Template Library,即标准模板库).

但是如果你全面了解过人们关于使用 STL 的各类看法,尤其是游戏行业人员关于 STL 使用的看法,你就会发现,不少人其实是反对使用 STL 的!

这就有点像 2020 年了,颇有些迷幻的味道:一方面有人觉得 STL 方便稳定,应该多多应用;另一方面又有人对 STL 避之不及,似乎其问题多多.

支持 STL 的理由在此不再赘述,大家应该都有所耳闻,我们这里主要来看看反对 STL 的各类观点(有一些观点,譬如 STL 跨平台支持不完善, STL 实现效率低等等,目前已经有了很大改善,可以认为已经不是问题了,下面不再列出):

从 STL 自身出发:

  • STL allocator 难以正确定制,缺少设置内存对齐(alignment)等功能
  • STL container 同样难以定制,并且存在不能保存引用,存在额外的内存开销(容器为空的情况下)等问题
  • STL 难以调试
  • STL 缺少某些需要的功能

从不使用 STL 的优点出发:

  • 可以对每处细节进行定制,优化实现效率,内存使用等方面的表现
  • 跨平台表现更加一致
  • 易于调试
  • 可以扩展更多功能

这里举个简单的例子,假设你现在需要维护一个集合数据(集合中的元素不能重复),你会选择怎样实现呢?

熟稔的朋友可能马上会想到 unordered_set:

  1. #include <unordered_set>
  2. std::unordered_set<int> std_unordered_set;

接着,你可能会发现集合元素的数量其实不多,需要的操作也很少(仅需要增删查),你当然可以继续沿用 unordered_set,但是你也可以定制一个更适用你当前使用场景的 unordered_set_lite:

  1. template<typename T, size_t capacity = 16>
  2. class unordered_set_lite {
  3. public:
  4. bool insert(T value) {
  5. for (size_t i = 0; i < m_count; ++i) {
  6. if (m_data[i] == value) {
  7. return false;
  8. }
  9. }
  10. if (m_count < capacity) {
  11. m_data[m_count] = value;
  12. ++m_count;
  13. return true;
  14. }
  15. return false;
  16. }
  17. bool erase(T value) {
  18. for (size_t i = 0; i < m_count; ++i) {
  19. if (m_data[i] == value) {
  20. m_data[i] = m_data[m_count - 1];
  21. --m_count;
  22. return true;
  23. }
  24. }
  25. return false;
  26. }
  27. bool contains(T value) const {
  28. for (size_t i = 0; i < m_count; ++i) {
  29. if (m_data[i] == value) {
  30. return true;
  31. }
  32. }
  33. return false;
  34. }
  35. size_t size() const {
  36. return m_count;
  37. }
  38. private:
  39. T m_data[capacity];
  40. size_t m_count = 0;
  41. };

unordered_set_lite 对比 unordered_set 有如下优点:

  • 更轻量(少)的代码实现
  • 更紧凑(少)的内存使用
  • 更高的运行效率(有 6 倍左右的提速)

在游戏业界, EASTL 应该是用于替换(不使用) STL 最知名的一个程序库了,有兴趣的朋友可以看看.另外的,了解 UE 的朋友可能也知道,在虚幻引擎中也使用了自己实现的一套模板库(TArray,TMap 等等),而没有使用 STL,曾有人就为何 UE 不使用 STL 提出过疑问,得到的答案大抵和上面的提到的观点相似,不过最后 Tim Sweeney 道出了主要原因:

其实 UE 选择自己实现模板库主要是历史遗留问题造成的, UE 发布初版的时候(1998年),当时的 STL 还很不成熟,跨平台表现更是糟糕,当时的 UE 自然不会选择使用 STL,而是改以实现自己的模板库代码,这些代码历经几代传承,也便沿用到了现在(UE4),同时 Tim 也表示目前的 STL 已经非常稳定,可以考虑在 UE 中逐步替换之前虚幻自己实现的模板库了.

回过头来我们再看看之前人们提出的各种 STL 的不足(或者不使用 STL 的优点),你会发现,其实这些论点都是基于特定的使用场景提出的,如果从更广阔的视角综合考虑的话,我们都能轻松的找到反驳这些观点的论据.

就拿上面那个 unordered_set_lite 来说,只要我们需要维护的元素越过了特定阈值,其性能就会落后于 unordered_set ,诚然,我们似乎可以往通用性的方向继续完善 unordered_set_lite,但是最后你会发现,自己只是又造了一个 unordered_set 的轮子,而且大概率还是一个更加简陋的轮子,但同时我们也不能否认,如果需要维护的元素确实不多的话,使用 unordered_set_lite 是要优于使用 unordered_set 的,总的来说, unordered_set_lite 与 unordered_set 的取舍仍然是一个工程问题,而工程问题,似乎永远都是一个权衡的游戏.

至此,我们便能理解上面那个迷幻问题了:为何人们对于是否使用 STL 的观点大相径庭了.

支持使用 STL 的人们基本是从更 generic 的角度出发的,而反对使用 STL 的人们基本是从更 specific 的角度出发的,两者看待问题的角度不同,得出的结论自然也就不同.

而所谓的 C++ 标准库的使用迷思,不过是不同角度看待 STL的产物罢了~

那么最后的问题来了,你看待 STL 目前是什么角度呢 ?

参考资料

  • Why doesn’t UE utilize STL containers?
  • Why do big projects like Unreal Engine write their own container classes?
  • EASTL – Electronic Arts Standard Template Library
  • Rocket and the STL

发表评论

表情:
评论列表 (有 0 条评论,203人围观)

还没有评论,来说两句吧...

相关阅读

    相关 AI测试的

    近年来,我一直关注AI相关的测试,并积极参与多个全国性测试社区和社群。在这些社区中,我与不同公司和领域的测试专家交流探讨AI测试相关话题,包括业界顶尖公司的专家和国内知名测试学

    相关 C++ 标准使用

    > 转眼 2020 已经过去,回顾来看总有些迷幻,新年之际,自己倒不打算写些什么年终总结,想想还是记一小篇技术小文: C++ 标准库的使用迷思. 了解 C++ 的朋友对于标准

    相关 之AI

    AI属于当下热点,但是阿里巴巴人工智能实验室(AI Labs)已经解散这一消息无疑给资本市场泼了一盆冷水。 AI就目前来看,仍然是一个高投入产出低的科研项目。研究人员的研究进

    相关 C++标准

        如果你有一定的C基础可能学起来比较容易些,但是学习[C++][C]的过程中又要尽量避免去使用一些C中的思想;平时还要多看一些高手写的代码,遇到问题多多思考,怎样才能把问

    相关 C++标准标准模板

      C++强大的功能来源于其丰富的类库及库函数资源。C++标准库的内容总共在50个标准头文件中定义。在C++开发中,要尽可能地利用标准库完成。这样做的直接好处包括:(1)成本: