3

C++ 标准库の使用迷思

 3 years ago
source link: https://blog.csdn.net/tkokof1/article/details/112107283
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C++ 标准库の使用迷思

tkokof1 2021-01-02 17:35:02 20

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

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

#include <vector>

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:

#include <unordered_set>

std::unordered_set<int> std_unordered_set;

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

template<typename T, size_t capacity = 16>
class unordered_set_lite {
public:
	bool insert(T value) {
		for (size_t i = 0; i < m_count; ++i) {
			if (m_data[i] == value) {
				return false;
			}
		}

		if (m_count < capacity) {
			m_data[m_count] = value;
			++m_count;
			return true;
		}

		return false;
	}

	bool erase(T value) {
		for (size_t i = 0; i < m_count; ++i) {
			if (m_data[i] == value) {
				m_data[i] = m_data[m_count - 1];
				--m_count;
				return true;
			}
		}

		return false;
	}

	bool contains(T value) const {
		for (size_t i = 0; i < m_count; ++i) {
			if (m_data[i] == value) {
				return true;
			}
		}

		return false;
	}

	size_t size() const {
		return m_count;
	}

private:
	T m_data[capacity];
	size_t m_count = 0;
};

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 目前是什么角度呢 ?


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK