STL之路 - 入门介绍篇

1、基本介绍:

 STL:C++的程序库,建立的数据结构与算法的一套标准

 核心思想:复用性的提升,复用性必须建立在某种标准之上

2、STL六大组件:

 (1)容器(container):各种数据结构,如vector,list,deque,set,map
(2)算法(algorithm):常用算法,如sort,erase
(3)迭代器(iterator):扮演容器与算法之间的胶合剂,是所谓的“泛型指针”
(4)仿函数(functor):行为类似函数,可作为算法的某种策略
(5)适配器(adapter):一种修饰容器或仿函数或迭代器接口的东西
(6)配置器(allocators):负责空间配置与管理

3、《STL源码剖析》这本书主要是以SGI STL版本进行讲解
(1)SGI STL文件可以分为五组:C++标准规范下的头文件(cstdio)、C++标准程序库中不属于STL范畴者(stream)、STL标准头文件(vector)、C++ standard定案前,HP所规范的STL头文件(vector.h)、SGI STL内部文件,STL真正实现(stl_vector.h)
(2)关于SGI STL的编译器组态设置
 1)组态设置:SGL STL的一个环境组态文件<stl_config.h>,其中定义了许多常量,标示某些组态的成立与否(因为不同的编译器对C++语言的支持程度不一样,为了广泛移植所以有了这个东西),所有的STL头文件都会直接或间接包含这个组态文件,以条件式写法,让预处理器根据各个常量决定取舍哪一段代码。
 

这是我我电脑上stl_config.h文件夹的部分内容

以下是测试代码:

#include<vector>
#include<iostream>
#include<cstdlib>

using namespace std;

int main()
{
#if defined(__sgi)
	cout << "__sgi" << endl;
#endif // defined(__sgi)

#if defined(__GUNC__)
	cout << "__GUNC__" << endl;
	cout << __GUNC__<< ' ' << __GUNC_MINOR__ << endl;
#endif // defined(_GUNC_)

#ifdef __STL_NO_DRAND48
	cout << "_STL_NO_DRAND48 defined" << endl;
#else
	cout << "_STL_NO_DRAND48 undefiend" << endl;
#endif // _STL_NO_DRAND48

#ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
	cout << "_STL_STATIC_TEMPLATE_MEMBER_BUG defined" << endl;
#else
	cout << "_STL_STATIC_TEMPLATE_MEMBER_BUG undefined" << endl;
#endif // _STL_STATIC_TEMPLATE_MEMBER_BUG

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
	cout << "_STL_CLASS_PARTIAL_SPECIALIZATION defined" << endl;
#else
	cout <<"_STL_CLASS_PARTIAL_SPECIALIZATION undefined" << endl;
#endif

#ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDER
	cout << "_STL_FUNCTION_TMPL_PARTIAL_ORDER defined" << endl;
#else
	cout << "_STL_FUNCTION_TMPL_PARTIAL_ORDER undefined" << endl;
#endif

#ifdef __STL_EXPLICIT_FUNCTION_TMPL_ARGS
	cout << "_STL_EXPLICIT_FUNCTION_TMPL_ARGS defined" << endl;
#else
	cout << "_STL_EXPLICIT_FUNCTION_TMPL_ARGS undefined" << endl;
#endif

#ifdef __STL_MEMBER_TEMPLATES
	cout << "__STL_MEMBER_TEMPLATES defined" << endl;
#else
	cout << "__STL_MEMBER_TEMPLATES undefined" << endl;
#endif

#ifdef __STL_LIMITED_DEFAULT_TEMPLATES
	cout << "__STL_LIMITED_DEFAULT_TEMPLATES defined" << endl;
#else
	cout << "__STL_LIMITED_DEFAULT_TEMPLATES undefined" << endl;
#endif

	system("PAUSE");
	return 0;
} 

在Ubuntu条件下测试全为undefined的,大概是测试方法问题,使用Cyswin B20测试,但是测试环境没有搭建好,无法输出


4、可能令你困惑的C++语法

(1)stl_config.h中的各种组态:

 在《STL源码剖析》中,举了几个例子,实际上就是测试编译器对这些组态的支持程度。这里仅以_STL_STATIC_TEMPLATE_MEMBER_BUG做一下举例说明,这个的意思是编译器是否接受静态成员的初值设定

测试代码:

#include<iostream>
using namespace std;

template <typename T>
class TestClass{
public:
	static int data;
};

template<> int TestClass<int>::data = 1;	//书上此处代码错了	
template<> int TestClass<char>::data = 2;

int main()
{
	//Testing enviorment:ubuntu gcc 
	cout << TestClass<int>::data<<endl;		//1	
	cout << TestClass<char>::data<<endl;		//2
}

余下的集中组态,也可以按照组态表达的意思(看英文),设计合适的测试对编译器是否支持该组态进行测试。目前由于姿势水平不够,在后期的学习中将对组态进行更进一步的阐述,目前先到这里了解概念。

(2)临时对象的产生以及运用:临时对象就是一种无名对象,出现不在程序员的预期内(比如pass by value引起的copy操作,形成了一个临时对象),往往会造成效率上的负担。但是有时刻意的使用临时对象,是一个是程序很爽的技巧。

刻意制造临时对象:在类型名称之后直接加一对小括号,指定初值,如shape(3, 5),其意义箱单于调用相应的constructor且不指定对象名称。STL最常将此技巧应用于仿函数与算法搭配上

(3)静态常量整数成员在class内部直接初始化:如果class内含const static type data member,那么根据C++标准规格,我们可以在class之内直接给予初值。


(4)increment/decrement/dereference操作符

 increment/dereference 操作符在迭代器的实现上占有非常重要的地位,因为任何一个迭代器都必须实现出前进(increment,operator++)和取值(dereference,operator*)功能,前者还分为前置式(prefix)和后置式(postfix)两种。其实就是++a,--a,以及取值操作符*

(5)前闭后开区间表示法[ ):任何一个STL算法,都需要获得由一对迭代器(泛型指针)所标示的区间,用以表示操作范围。这一对迭代器所标示的是个所谓的前闭后开的区间,以[first, last)表示。也就是说,整个实际范围从first开始,知道last - 1。迭代器last并不含元素,它指的的是“最后一个元素的下一个位置”。这标示法叫off by one(或说是pass yje end),一个小技巧。

 用过C++容器都知道,Iterator遍历整个容器,一般是从begin()开始到end()

(6)function call操作符( operator() )

        函数调用操作(左右小括号)也可以被重载

STL算法中很多都提供了两个版本,一个用于一般情况(例如递增排序),一个用于特殊情况(相当于自定义排序规则,在C语言
时代往往通过传递一个函数指针来实现) 。所以在这种情况下,需要用户指定某个条件或者策略,而条件和策略的背后由一整组操
作构成,便需要某种特殊的东西来代表这“一整组操作”
在C语言时代,代表“一整组操作”的是函数,通过函数指针来完成。但是函数指针有缺点,最重要的是他无法持有自己的状态
,也无法达到组件技术中的可适配性(个人理解是:在C语言里面,假设定义了一个规则(函数),然后使用函数指针进行传递,但是这种
但是它使用的范围有限,只能在一些场合使用,同时函数指针名作为函数的指针是不可变——关于这句话的理解“无法再将某些修饰条件
加诸其上而改变其状态,我的理解是,一旦你在程序中写下一段代码使用了函数指针,那么这个函数指针是不可变的,函数指针无法向一些
类型一样自由赋值)
因此,STL算法的特殊版本所接受的所谓”条件“,都已仿函数形式呈现。仿函数(functor)就是使用起来向函数一样的东西。如果对
某个class进行operator()重载,他就是一个仿函数。





猜你喜欢

转载自blog.csdn.net/qq_37925512/article/details/79125370