STL源码剖析—stl_config
操作系统:centos 6.4
STL源码版本:3.3
前言:
要看一个项目的源码,首先要选中切入点。
那么在sgi stl 标准库中,其切入点是什么呢?
答案是:stl_config.h 文件。
不同的编译器对C++语言的支持程度不尽相同。为了具备广泛移植能力,SGI STL 定义了一个环境组态文件<stl_config.h>。
其中声明了许多宏定义,在预编译的时候,通过这些宏定义来编译出对于平台的程序。
1,stl_config.h在linux平台下的实现:
1.1)为了知道linux平台下sgi stl 的宏定义有那些是被定义了的,有个简单,直接的方法,直接输出其宏名字。
测试代码如下:
#include <iostream> #include <stdio.h> using namespace std; void test(void) { #ifdef _PTHREADS cout<<"define __STL_PTHREADS"<<endl; #endif # if defined(__sgi) && !defined(__GNUC__) cout<<"__sgi begin"<<endl; # if !defined(_BOOL) cout<<"__STL_NEED_BOOL"<<endl; # endif # if !defined(_TYPENAME_IS_KEYWORD) cout<<"__STL_NEED_TYPENAME"<<endl; # endif # ifdef _PARTIAL_SPECIALIZATION_OF_CLASS_TEMPLATES cout<<"__STL_CLASS_PARTIAL_SPECIALIZATION"<<endl; # endif # ifdef _MEMBER_TEMPLATES cout<<"__STL_MEMBER_TEMPLATES"<<endl; # endif # if !defined(_EXPLICIT_IS_KEYWORD) cout<<"__STL_NEED_EXPLICIT"<<endl; # endif # ifdef __EXCEPTIONS cout<<"__STL_USE_EXCEPTIONS"<<endl; # endif # if (_COMPILER_VERSION >= 721) && defined(_NAMESPACES) cout<<"__STL_USE_NAMESPACES"<<endl; # endif # if !defined(_NOTHREADS) && !defined(__STL_PTHREADS) cout<<"__STL_SGI_THREADS"<<endl; # endif cout<<"__sgi end"<<endl<<endl; # endif # ifdef __GNUC__ cout<<"__GNUC__ begin"<<endl; # include <_G_config.h> # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) cout<<"__STL_STATIC_TEMPLATE_MEMBER_BUG"<<endl; cout<<"__STL_NEED_TYPENAME"<<endl; cout<<"__STL_NEED_EXPLICIT"<<endl; # else cout<<"__STL_CLASS_PARTIAL_SPECIALIZATION"<<endl; cout<<"__STL_FUNCTION_TMPL_PARTIAL_ORDER"<<endl; cout<<"__STL_EXPLICIT_FUNCTION_TMPL_ARGS"<<endl; cout<<"__STL_MEMBER_TEMPLATES"<<endl; # endif /* glibc pre 2.0 is very buggy. We have to disable thread for it. It should be upgraded to glibc 2.0 or later. */ # if !defined(_NOTHREADS) && __GLIBC__ >= 2 && defined(_G_USING_THUNKS) cout<<"__STL_PTHREADS"<<endl; # endif # ifdef __EXCEPTIONS cout<<"__STL_USE_EXCEPTIONS"<<endl; # endif cout<<"__GNUC__ end"<<endl<<endl; # endif # if defined(__SUNPRO_CC) cout<<"__SUNPRO_CC begin"<<endl; cout<<"__STL_NEED_BOOL"<<endl; cout<<"__STL_NEED_TYPENAME"<<endl; cout<<"__STL_NEED_EXPLICIT"<<endl; cout<<"__STL_USE_EXCEPTIONS"<<endl; cout<<"__SUNPRO_CC end"<<endl<<endl; # endif # if defined(__COMO__) cout<<"__COMO__ begin"<<endl; cout<<"__STL_MEMBER_TEMPLATES"<<endl; cout<<"__STL_CLASS_PARTIAL_SPECIALIZATION"<<endl; cout<<"__STL_USE_EXCEPTIONS"<<endl; cout<<"__STL_USE_NAMESPACES"<<endl; cout<<"__COMO__ end"<<endl<<endl; # endif # if defined(_MSC_VER) cout<<"_MSC_VER begin"<<endl; # if _MSC_VER > 1000 cout<<"include <yvals.h>"<<endl; # else cout<<"__STL_NEED_BOOL"<<endl; # endif cout<<"__STL_NO_DRAND48"<<endl; cout<<"__STL_NEED_TYPENAME"<<endl; # if _MSC_VER < 1100 cout<<"__STL_NEED_EXPLICIT"<<endl; # endif cout<<"__STL_NON_TYPE_TMPL_PARAM_BUG"<<endl; cout<<"__SGI_STL_NO_ARROW_OPERATOR"<<endl; # ifdef _CPPUNWIND cout<<"__STL_USE_EXCEPTIONS"<<endl; # endif # ifdef _MT cout<<"__STL_WIN32THREADS"<<endl; # endif cout<<"_MSC_VER end"<<endl<<endl; # endif # if defined(__BORLANDC__) cout<<"__BORLANDC__ begin"<<endl; cout<<"__STL_NO_DRAND48"<<endl; cout<<"__STL_NEED_TYPENAME"<<endl; cout<<"__STL_LIMITED_DEFAULT_TEMPLATES"<<endl; cout<<"__SGI_STL_NO_ARROW_OPERATOR"<<endl; cout<<"__STL_NON_TYPE_TMPL_PARAM_BUG"<<endl; # ifdef _CPPUNWIND cout<<"__STL_USE_EXCEPTIONS"<<endl; # endif # ifdef __MT__ cout<<"__STL_WIN32THREADS"<<endl; # endif cout<<"__BORLANDC__ end"<<endl<<endl; # endif # if defined(__STL_NEED_BOOL) cout<<"__STL_NEED_BOOL begin"<<endl; cout<<"typedef int bool;"<<endl; cout<<"define true 1"<<endl; cout<<"define false 0"<<endl; cout<<"__STL_NEED_BOOL end"<<endl<<endl; # endif # ifdef __STL_NEED_TYPENAME cout<<"define typename"<<endl; # endif # ifdef __STL_NEED_EXPLICIT cout<<"define explicit"<<endl; # endif # ifdef __STL_EXPLICIT_FUNCTION_TMPL_ARGS cout<<"__STL_NULL_TMPL_ARGS <>"<<endl; # else cout<<"__STL_NULL_TMPL_ARGS"<<endl; # endif # ifdef __STL_CLASS_PARTIAL_SPECIALIZATION cout<<"__STL_TEMPLATE_NULL template<>"<<endl; # else cout<<"__STL_TEMPLATE_NULL"<<endl; # endif // __STL_NO_NAMESPACES is a hook so that users can disable namespaces // without having to edit library headers. # if defined(__STL_USE_NAMESPACES) && !defined(__STL_NO_NAMESPACES) cout<<"__STL_USE_NAMESPACES begin"<<endl; cout<<"__STD std"<<endl; cout<<"__STL_BEGIN_NAMESPACE namespace std {"<<endl; cout<<"__STL_END_NAMESPACE }"<<endl; cout<<"__STL_USE_NAMESPACE_FOR_RELOPS"<<endl; cout<<"__STL_BEGIN_RELOPS_NAMESPACE namespace std {"<<endl; cout<<"__STL_END_RELOPS_NAMESPACE }"<<endl; cout<<"__STD_RELOPS std"<<endl; cout<<"__STL_USE_NAMESPACES end"<<endl<<endl; # else cout<<"! __STL_USE_NAMESPACES begin"<<endl; cout<<"__STD "<<endl; cout<<"__STL_BEGIN_NAMESPACE "<<endl; cout<<"__STL_END_NAMESPACE "<<endl; cout<<"__STL_USE_NAMESPACE_FOR_RELOPS"<<endl; cout<<"__STL_BEGIN_RELOPS_NAMESPACE "<<endl; cout<<"__STL_END_RELOPS_NAMESPACE "<<endl; cout<<"__STD_RELOPS "<<endl; cout<<"! __STL_USE_NAMESPACES end"<<endl<<endl; # endif # ifdef __STL_USE_EXCEPTIONS cout<<"__STL_USE_EXCEPTIONS begin"<<endl; cout<<"__STL_TRY try"<<endl; cout<<"__STL_CATCH_ALL catch(...)"<<endl; cout<<"__STL_RETHROW throw"<<endl; cout<<"__STL_NOTHROW throw()"<<endl; cout<<"__STL_UNWIND(action) catch(...) { action; throw; }"<<endl; cout<<"__STL_USE_EXCEPTIONS end"<<endl<<endl; # else cout<<"! __STL_USE_EXCEPTIONS begin"<<endl; cout<<"__STL_TRY "<<endl; cout<<"__STL_CATCH_ALL if (false)"<<endl; cout<<"__STL_RETHROW "<<endl; cout<<"__STL_NOTHROW "<<endl; cout<<"__STL_UNWIND(action) "<<endl; cout<<"! __STL_USE_EXCEPTIONS end"<<endl<<endl; # endif #ifdef __STL_ASSERTIONS # include <stdio.h> cout<<"__stl_assert(expr) \ if (!(expr)) { fprintf(stderr, \"%s:%d STL assertion failure: %s\n\", \ __FILE__, __LINE__, # expr); abort(); }"<<endl; #else cout<<"__stl_assert(expr)"<<endl; #endif } int main(void) { test(); return 0; }
运行结果:
[root@localhost stlsource]# g++ -o lconfig1 lconfig1.cpp [root@localhost stlsource]# ./lconfig1 __GNUC__ begin __STL_CLASS_PARTIAL_SPECIALIZATION __STL_FUNCTION_TMPL_PARTIAL_ORDER __STL_EXPLICIT_FUNCTION_TMPL_ARGS __STL_MEMBER_TEMPLATES __STL_PTHREADS __STL_USE_EXCEPTIONS __GNUC__ end __STL_NULL_TMPL_ARGS __STL_TEMPLATE_NULL ! __STL_USE_NAMESPACES begin __STD __STL_BEGIN_NAMESPACE __STL_END_NAMESPACE __STL_USE_NAMESPACE_FOR_RELOPS __STL_BEGIN_RELOPS_NAMESPACE __STL_END_RELOPS_NAMESPACE __STD_RELOPS ! __STL_USE_NAMESPACES end ! __STL_USE_EXCEPTIONS begin __STL_TRY __STL_CATCH_ALL if (false) __STL_RETHROW __STL_NOTHROW __STL_UNWIND(action) ! __STL_USE_EXCEPTIONS end __stl_assert(expr)
1.2)通过以上的测试,可以得到在linux平台下,stl_config.h 的实现定义如下:
为了缩小篇幅,把相关的版权信息的屏蔽了。
#ifndef __STL_CONFIG_H # define __STL_CONFIG_H # ifdef __GNUC__ # include <_G_config.h> # define __STL_CLASS_PARTIAL_SPECIALIZATION # define __STL_FUNCTION_TMPL_PARTIAL_ORDER # define __STL_EXPLICIT_FUNCTION_TMPL_ARGS # define __STL_MEMBER_TEMPLATES # define __STL_PTHREADS # define __STL_USE_EXCEPTIONS # endif # define __STL_NULL_TMPL_ARGS # define __STL_TEMPLATE_NULL # define __STD # define __STL_BEGIN_NAMESPACE # define __STL_END_NAMESPACE # undef __STL_USE_NAMESPACE_FOR_RELOPS # define __STL_BEGIN_RELOPS_NAMESPACE # define __STL_END_RELOPS_NAMESPACE # define __STD_RELOPS # define __STL_TRY # define __STL_CATCH_ALL if (false) # define __STL_RETHROW # define __STL_NOTHROW # define __STL_UNWIND(action) # define __stl_assert(expr) #endif /* __STL_CONFIG_H */ // Local Variables: // mode:C++ // End:
2,对stl_config.h中的宏的详解:
2.1)__STL_STATIC_TEMPLATE_MEMBER_BUG
- 如果编译器不支持static members of template classes(模板类静态成员),
- // 则定义__STL_STATIC_TEMPLATE_MEMBER_BUG
#include<iostream> using namespace std; template <typename T> class testClass { public: static int _data; }; //只对成员实现特化,记得加上template<> template<> int testClass<int>::_data=1; template<> int testClass<char>::_data=2; int main() { cout<<testClass<int>::_data<<endl; cout<<testClass<char>::_data<<endl; testClass<int> Obji1,Obji2; testClass<char> Objc1,Objc2; cout<<Obji1._data<<endl; cout<<Obji2._data<<endl; cout<<Objc1._data<<endl; cout<<Objc2._data<<endl; Obji1._data=3; Objc1._data=4; cout<<Obji1._data<<endl; cout<<Obji2._data<<endl; cout<<Objc1._data<<endl; cout<<Objc2._data<<endl; }
运行结果:
[root@localhost stlsource]# ./lconfig3 1 2 1 1 2 2 3 3 4 4
2.2)__STL_CLASS_PARTIAL_SPECIALIZATION
- 如果编译器支持partial specialization of class templates(局部特殊化的类模板),
- // 则定义__STL_CLASS_PARTIAL_SPECIALIZATION
- // 参考文献: http://msdn.microsoft.com/en-us/library/9w7t3kf1(v=VS.71).aspx
#include<iostream> using namespace std; template <class I,class O> struct testClass { testClass() {cout<<"I,O"<<endl;} }; //对类实现偏特化 template <class T> struct testClass<T*,T*> { testClass() {cout<<"T*,T*"<<endl;} }; //对类实现偏特化 template<class T> struct testClass<const T*,T*> { testClass(){ cout<<"const T*,T*"<<endl;} }; int main() { testClass<int,char> obj1; testClass<int*,int*> obj2; testClass<const int*,int*> obj3; }
运行结果:
[root@localhost stlsource]# ./lconfig5 I,O T*,T* const T*,T*
2.3)__STL_FUNCTION_TMPL_PARTIAL_ORDER
- 如果编译器支持partial ordering of function templates(部分排序函数模板),
- // 则定义__STL_FUNCTION_TMPL_PARTIAL_ORDER
- // 参考资料: http://msdn.microsoft.com/zh-cn/library/zaycz069.aspx
#include<iostream> using namespace std; class alloc{ }; template <class T,class Alloc=alloc> class vector{ public: void swap(vector<T,Alloc>&) {cout<<"swap()"<<endl;} }; //本来是#ifdef__STL_FUNCION_TMPL_PARTIAL_ORDER,但是貌似不支持 #ifndef __STL_FUNCION_TMPL_PARTIAL_ORDER template <class T,class Alloc> inline void swap(vector<T,Alloc>& x,vector<T,Alloc>& y) { x.swap(y); } #endif // __STL_FUNCION_TMPL_PARTIAL_ORDER int main() { vector<int>x,y; swap(x,y); }
运行结果:
[root@localhost stlsource]# ./lconfig6
swap()
2.4)__STL_EXPLICIT_FUNCTION_TMPL_ARGS
整个 SGI STL 内都没有用到此一常数定义
- 如果编译器支持calling a function template by providing its template
- // arguments explicitly(显式指定调用模板函数的模板参数)
2.5)__STL_MEMBER_TEMPLATES
- 如果编译器支持template members of classes(类模板成员),
- // 则定义__STL_MEMBER_TEMPLATES
#include<iostream> #include<typeinfo> using namespace std; class alloc{ }; //类模板 template <typename T,typename Alloc=alloc> class vector{ public: typedef T value_type; typedef value_type* iterator; //函数模板 template <typename I> void insert(iterator position,I first,I last) { cout<<"insert()"<<endl; cout<<typeid(I).name()<<endl; } }; int main() { int ia[5]={0,1,2,3,4}; vector<int> x; vector<int>::iterator ite; x.insert(ite,*ia,*(ia+5)); }
运行结果:
[root@localhost stlsource]# ./lconfig8
insert()
i
2.6)__STL_LIMITED_DEFAULT_TEMPLATES
- 如果编译器不能根据前一个模板参数设定后面的默认模板参数,
- // 则定义__STL_LIMITED_DEFAULT_TEMPLATES
#include<iostream> #include<cstddef> using namespace std; class alloc{}; template <typename T,class Alloc=alloc,size_t Bufsiz=0> class deque{ public: deque(){cout<<"deque"<<endl;} }; template <typename T,class Sequence=deque<T> > class stack{ public: stack(){ cout<<"stack"<<endl;} private: Sequence c;//调用deque的构造函数初始化 }; int main() { stack<int> x; }
运行结果:
[root@localhost stlsource]# ./lconfig10 deque stack
2.7)__STL_NON_TYPE_TMPL_PARAM_BUG
- 如果编译器处理模板函数的non-type模板参数类型推断有困难,
- // 则定义__STL_NON_TYPE_TMPL_PARAM_BUG
#include<iostream> #include<cstddef> using namespace std; class alloc{}; inline size_t __deque_buf_size(size_t n,size_t sz) { return n!=0?n:(sz<512?size_t(512/sz):size_t(1)); } template <class T,class Ref,class Ptr,size_t Bufsiz> struct __deque_iterator{ typedef __deque_iterator<T,T&,T*,Bufsiz> iterator; typedef __deque_iterator<T,const T&,const T*,Bufsiz> const_iterator; static size_t buffer_size() {return __deque_buf_size(Bufsiz,sizeof(T));} }; template <class T,class Alloc=alloc,size_t Bufsiz=0> class deque { public: typedef __deque_iterator<T,T&,T*,Bufsiz> iterator; }; int main() { cout<<deque<int>::iterator::buffer_size()<<endl; cout<<deque<int,alloc,64>::iterator::buffer_size()<<endl; }
运行结果:
2.8)__STL_NULL_TMPL_ARGS(bound friend template friend)
<stl_config.h>定义__STL_NULL_TMPL_ARGS如下:
#ifdef __STL_NULL_TMPL_ARGS # define __STL_NULL_TMPL_ARGS <> #else # define __STL_NULL_TMPL_ARGS #endif
这个组态常量常常出现在类似这样的场合(class template的friend函数声明)。
// in <stl_stack.h> template<class T,class Sequence=deque<T> > class stack{ friend bool operator==___STL_NULL_TMPL_ARGS(const stack &,const stack&); friend bool operator< __STL_NULL_TMPL_ARGS(const stack&,const stack&); ... }; 展开后就变成了: template<class T,class Sequence=deque<T> > class stack{ friend bool operator== <>(const stack &,const stack&); friend bool operator< <>(const stack&,const stack&); ... };
这种奇特的语法是为了实现所谓的 bound friend templates,也就是说class template的某个具现体(instantiation)与其friend function template的某个具现体有一对一的关系。下面是测试程序:
#include<iostream> #include<cstddef> using namespace std; class alloc{}; template<class T,class Alloc=alloc,size_t BufSiz=0> class deque { public: deque(){cout<<"deque"<<endl;} }; //类模板与友元的一对一关系需要前置声明 template<class T,class Sequence> class stack; template<class T,class Sequence> bool operator==(const stack<T,Sequence>& x,const stack<T,Sequence>& y); template<class T,class Sequence> bool operator<(const stack<T,Sequence>& x,const stack<T,Sequence>& y); template<class T,class Sequence=deque<T> > class stack { //friend bool operator==<T>(const stack<T>&,const stack<T>&); //friend bool operator< <T>(const stack<T>&,const stack<T>&); //下面的都是等价于上面的 //friend bool operator== <T>(const stack&,const stack&); //friend bool operator< <T>(const stack&,const stack&); friend bool operator== <>(const stack&,const stack&); friend bool operator< <>(const stack&,const stack&); public: stack(){cout<<"stack"<<endl;} private: Sequence c; }; template<class T,class Sequence> bool operator==(const stack<T,Sequence> &x,const stack<T,Sequence> &y) { return cout<<"operator=="<<'\t'; } template<class T,class Sequence> bool operator<(const stack<T,Sequence> &x,const stack<T,Sequence> &y) { return cout<<"operator<"<<'\t'; } int main() { stack<int> x; stack<int> y; cout<<(x==y)<<endl; cout<<(x<y)<<endl; stack<char> y1; // cout<<(x==y1)<<endl; // cout<<(x<y1)<<endl; }
运行结果:
2.9)__STL_TEMPLATE_NULL(class template explicit specialization)
<stl_config.h>定义了一个__STL_TEMPLATE_NULL如下:
#ifdef __STL_CLASS_PAPTIAL_SPECIALIZATION #define __STL_TEMPLATE_NULL template<> #else #define __STL_TEMPLATE_NULL #endif
这个组态常量常常出现在类似这样的场合:
//in <type_traits.h> template <class type> struct _type_traits {...}; __STL_TEMPLATE_NULL struct _type_traits<char> {}; //in <stl_hash_fun.h> template <class key> struct hash{}; __STL_TEMPLATE_NULL struct hash<char> {}; __STL_TEMPLATE_NULL struct hash<unsigned char> {};
展开后:
//in <type_traits.h> template <class type> struct _type_traits {...}; template<> struct _type_traits<char> {}; //in <stl_hash_fun.h> template <class key> struct hash{}; template<> struct hash<char> {}; template<> struct hash<unsigned char> {};
这就是所谓的class template explicit specialization。
下面是一个测试程序:
#include<iostream> //不能使用 using namespace std 这会将标准库中的hash引入,然后通不过 using std::cout; using std::endl; //貌似我使用g++编译,定义为空不能通过 //#define __STL_TEMPLATE_NULL #define __STL_TEMPLATE_NULL template<> template <class key> struct hash { //重载函数调用运算符 void operator()() { cout<<"hash<T>"<<endl; } }; template<> struct hash<char> { void operator()() { cout<<"hash<char>"<<endl; } }; __STL_TEMPLATE_NULL struct hash<unsigned char> { void operator()() { cout<<"hash<unsigned char"<<endl; } }; int main() { hash<long> t1; hash<char> t2; hash<unsigned char> t3; t1();//函数对象和函数指针类似,可以作为可调用对象 t2(); t3(); }
运行结果: