是否应该使用STL

       我们常常会听到关于STL存在各种问题的言论,甚至在某些公司的项目中,会禁用STL。所以很多新手C++程序员往往会对STL抱有很大的疑惑,不知道是否值得学习?

       “不熟悉C++标准库,任何人都不能称得上是高生产力的C++程序员”,这句话来自于《C++标准库》,的确库作为语言的一部分,本身就是为了帮助我们提高生产效率。

       大家对于STL的疑惑大概有以下4个:1.编译器对STL支持不好,调试困难;2.内存碎片;3.效率问题;4.难以使用,学习成本高。

编译器支持不好

       在初学C/C++时,我们常常将VC6作为IDE。在使用VC6编写STL程序时,我们总是会遇到很多莫名的告警错误,程序出错了,也难以调试。这就让大家对STL留下了不好的印象。但是,STL诞生于1994年,在1998年时才正式加入到C++标准中。所以当我们使用VC6这种相对古老的编译器时,往往会有各种各样奇怪的问题。但是,十多年过去了,很多新版本的编译器对STL的支持明显改善,也不会有各种奇怪的告警。

内存碎片及效率问题

       存在这两个问题的主要原因是容器内部可能存在大量的malloc,大量的malloc会导致内存利用率低下以及内存碎片化。为什么会导致利用率底下呢?

       假如我们执行如下代码:malloc(sizeof(int));,系统仅仅分配了4个字节的内存吗?并不是,系统会额外分配很多的cookie用于管理这部分的内存,大概为40-50个字节,这就导致一个问题,我们实际只使用到4个资源的内存但是却需要分配40多个字节,造成了大量的浪费。

int_memory

int main()
{
	long count = 25000000;
	std::list<int> lst;
	for (long i=0; i<count; i++)
	{
		lst.push_back(3);
	}
	cout << "ok" <<endl;
	Sleep(100000);
	return 0;
}

执行上述代码,观察进程管理器,得到如下变化:

list_memory

       我们在list容器中总共存入了25 000 000个int元素,占100MB的内存,但是实际占用了1.23g。但是要是将list容器替换成vector。

int main()
{
	long count = 25000000;
	std::vector<int> vct;
	for (long i=0; i<count; i++)
	{
		vct.push_back(3);
	}
	cout << "ok" <<endl;
	Sleep(100000);
	return 0;
}

执行上述代码,观察进程管理器,得到如下变化:

       使用vector后,同样是25 000 000个int元素,占了100MB内存。为什么会产生这种差异呢?原因是list容器是基于节点的。所以,当push_back时,就会malloc一个小内存,上述代码会有25 000 000次malloc。而vector是连续内存的,如果空间不够,会进行重新申请内存,并释放原来的内存。所以,就算有25 000 000个元素,其所有内存都是通过一次malloc获得的。这是造成内存利用率大大降低的原因。

       但是上诉问题在STL中是有办法解决的,SGI2.9的STL版本中,默认使用的alloc(在4.9版本中为_pool_alloc)通过内存池的方法解决此问题(关于这个alloc会通过其他文章进行介绍)。同样内存碎片问题也可以通过内存池的方法进行解决。通过malloc少次数大内存来代替多次数小内存。那要是服务器程序要运行很长时间,怎么办呢?我在知乎上看到一个陈硕的答案是:在谷歌,没有哪一台服务器是不能被重启的。的确一个好的架构本身就拥有很高的容错率,重启一台机器,并不会影响到整体的运行。相反,如果我们设计的架构中要求某台服务器必须长时间运行,那本身架构就存在问题。而且,就运行效率而言,因为STL是模板,所以效率并不差,但是编译的时候会稍微慢一点。

学习成本高

       的确,C++本身就比较难以掌握,STL中存在的种种陷阱,很容易使得新手犯错。但是,只要你静下心来,去了解一些各个容器的内部结构,尝试使用一些算法。就花这少许的时间,我们就可以利用这个宝库,不用再去写各种数据结构,算法,同时用STL写出的代码具有更高的可读性。

posted on 2016-01-22 19:29  帅帅帅帅  阅读(350)  评论(0编辑  收藏  举报