STL是英文standard template library的简写,中文名标准模板库。我们今天不说它的容器呀,迭代器呀,匹配器呀,算法呀这些,单说它的library。
然而,此库非彼库。STL的L虽然也是库,但这个库与已往的库有一些在本质上的差异。这怕是一个刚学编程的六岁半的小孩所不知道的吧。好了,闲言少叙,下面进入正题。
先从库的老祖宗lib说起。要使用lib库必需要有两个文件。一个文件是.h的,是库的头文件,用来说明库里有什么可用的内容。一个文件是.lib的,是库的实现文件,是库的具体实现,同时它里面也包含了一些定位信息。这种库被人们叫做静态库。因为这种的库的使用方式是:在链接的过程中,直接就链入我们的目标文件了。
再说现在比较流行的动态库。动态库一般会向外公开三个文件。以windows的动态库为例:一个文件是.h,一个文件是.lib,一个文件是.dll。.h文件的作用和静态库的一样,.lib的作用是包含一些导出信息。.dll文件中包含真正的实现和定位信息。
对比上面的两种库,我们发现.h文件是它们中必不可少的。这是因为.h所担当的角色:说明库里有什么可用的内容,而决定的。少了这个说明,这个库可怎么用呀。你能这样和别人说吗?“我给你一个库,你去用吧,但这个库没有用法”。所以,不论是静态库还是动态库,都向外提供一个.h文件来说明这个库的用法和内容。.h文件就象是库的一个微型说明书。
最后我们看STL的库。这种库只提供一种文件,而且没有任何扩展名。这样做的意思是说:“我可以一顶二(对于静态库来说),我可以一顶三(对于动态库来说)”。
STL的库确实是可以一顶二,一顶三。但它这样做却破坏了一个重要的软件原则:说明和实现分开。说明和实现分开这个原则可以为软件的升级和复用带来很多好处。说明为使用方和提供方之间建立了一个协议,双方只要遵守这个协议,提供方就可以很方便的修改实现部分,而不会对使用方添加麻烦。
可以STL却把说明和实现放到一块了。这就是说STL中想要改变一下实现,会对使用了STL的用户带来非常大的影响。下面我针对这个举一个例子。
假设现在我们要做一个库(不管是动态库,还是静态库):它的头文件如下:
#ifndef TEST_H
#define TEST_H
void output(std::string& arg);
#endif
这个库的功能很简单,只向外提供一个output函数。而这个output函数的用法也很简单。只有一个string的参数。写出这样一个简单的库,对于任何程序员来说都是一个非常容易的事。可是就是这个简单的库里面却有一颗定时炸弹。这个炸弹随时可能爆炸,把用户的程序炸崩溃。当用户气哼哼的找你的时候,你就知道STL把说明和实现放到一块的坏处了。原来,用户哪儿的,string和你库是的string不是一个版本的。那个炸弹爆了。
这也就是说如果你的程序要和其它的程序以STL的类型交换数据的话,你就要做好连源码一起发步出去的准备。且不说把源码发步出去带来的维护上的灾难。但就保密问题而言,你的源码是能轻易对外发步的吗?
当然,我们不能因为STL有这个毛病就否定STL的丰功伟绩。但STL确实是代码复用道路上的一次倒退。我们可以注意到,象loki,boost这些库,就没有再用一个没任何扩展名的一个文件来做一顶二,一顶三这样的事情。而是使用有了.h(.hpp)这样的做法。明明确确的告诉用户这是一个说明。
也许STL的L就不应该叫做库。要是非要叫库的话,应该把它和静态库及动态库区别开来。