STL源碼剖析—stl_config

操做系統:centos 6.4
STL源碼版本:3.3linux

前言:
    要看一個項目的源碼,首先要選中切入點。
    那麼在sgi stl 標準庫中,其切入點是什麼呢?
    答案是:stl_config.h 文件。

    不一樣的編譯器對C++語言的支持程度不盡相同。爲了具有普遍移植能力,SGI STL  定義了一個環境組態文件<stl_config.h>。
其中聲明瞭許多宏定義,在預編譯的時候,經過這些宏定義來編譯出對於平臺的程序。


1,stl_config.h在linux平臺下的實現:
    
    1.1)爲了知道linux平臺下sgi stl 的宏定義有那些是被定義了的,有個簡單,直接的方法,直接輸出其宏名字。
        測試代碼以下:ios

#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;
}

運行結果:centos

[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 測試

    1. 若是編譯器不支持static members of template classes(模板類靜態成員),  
    2. //       則定義__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;
}

運行結果:spa

[root@localhost stlsource]# ./lconfig3 
1
2
1
1
2
2
3
3
4
4

   2.2)__STL_CLASS_PARTIAL_SPECIALIZATION操作系統

    1. 若是編譯器支持partial specialization of class templates(局部特殊化的類模板),  
    2. //       則定義__STL_CLASS_PARTIAL_SPECIALIZATION  
    3. //       參考文獻: 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;
}

運行結果:3d

[root@localhost stlsource]# ./lconfig5
I,O
T*,T*
const T*,T*

    2.3)__STL_FUNCTION_TMPL_PARTIAL_ORDER指針

    1. 若是編譯器支持partial ordering of function templates(部分排序函數模板),  
    2. //       則定義__STL_FUNCTION_TMPL_PARTIAL_ORDER  
    3. //       參考資料: 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);
}

運行結果:code

[root@localhost stlsource]# ./lconfig6 
swap()

    2.4)__STL_EXPLICIT_FUNCTION_TMPL_ARGS 
        整個 SGI STL  內都沒有用到此一常數定義

    1. 若是編譯器支持calling a function template by providing its template  
    2. //       arguments explicitly(顯式指定調用模板函數的模板參數) 

    2.5)__STL_MEMBER_TEMPLATES 

  1. 若是編譯器支持template members of classes(類模板成員),  
  2. //       則定義__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

    1. 若是編譯器不能根據前一個模板參數設定後面的默認模板參數,  
    2. //       則定義__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 

    1. 若是編譯器處理模板函數的non-type模板參數類型推斷有困難,  
    2. //       則定義__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();
}

  運行結果:

相關文章
相關標籤/搜索