[c++] Let's dissect STL

源码在哪里


gcc & g++

gcc 最开始的时候是 GNU C Compiler, 如你所知,就是一个c编译器。但是后来因为这个项目里边集成了更多其他不同语言的编译器,GCC就代表 the GNU Compiler Collection,所以表示一堆编译器的合集。 g++则是GCC的c++编译器。

现在你在编译代码时调用的gcc,已经不是当初那个c语言编译器了,更确切的说他是一个驱动程序,根据代码的后缀名来判断调用c编译器还是c++编译器 (g++)。比如你的代码后缀是*.c,他会调用c编译器还有linker去链接c的library。如果你的代码后缀是cpp, 他会调用g++编译器,当然library call也是c++版本的。

 

源代码下载

Official web: GCC: Anonymous read-only Git access

Download source code: http://ftp.gnu.org/gnu/gcc/

 

STL相关文件

通过模板写的 .tcc文件.

复制代码
gcc-4.9.4$ find ./libstdc++-v3/include/bits/ -name "*.tcc"
./libstdc++-v3/include/bits/basic_ios.tcc ./libstdc++-v3/include/bits/valarray_array.tcc ./libstdc++-v3/include/bits/fstream.tcc ./libstdc++-v3/include/bits/locale_classes.tcc ./libstdc++-v3/include/bits/streambuf.tcc ./libstdc++-v3/include/bits/sstream.tcc ./libstdc++-v3/include/bits/regex.tcc ./libstdc++-v3/include/bits/locale_facets.tcc ./libstdc++-v3/include/bits/vector.tcc ./libstdc++-v3/include/bits/forward_list.tcc ./libstdc++-v3/include/bits/locale_facets_nonio.tcc ./libstdc++-v3/include/bits/regex_compiler.tcc ./libstdc++-v3/include/bits/random.tcc ./libstdc++-v3/include/bits/regex_automaton.tcc ./libstdc++-v3/include/bits/regex_executor.tcc ./libstdc++-v3/include/bits/istream.tcc ./libstdc++-v3/include/bits/basic_string.tcc ./libstdc++-v3/include/bits/deque.tcc ./libstdc++-v3/include/bits/regex_scanner.tcc ./libstdc++-v3/include/bits/ostream.tcc ./libstdc++-v3/include/bits/list.tcc
复制代码

相关的头文件.

复制代码
jeffrey@unsw-ThinkPad-T490:gcc-4.9.4$ find . -name "stl_*"
./libstdc++-v3/include/bits/stl_heap.h ./libstdc++-v3/include/bits/stl_tree.h ./libstdc++-v3/include/bits/stl_multimap.h ./libstdc++-v3/include/bits/stl_list.h ./libstdc++-v3/include/bits/stl_deque.h ./libstdc++-v3/include/bits/stl_iterator.h ./libstdc++-v3/include/bits/stl_construct.h ./libstdc++-v3/include/bits/stl_set.h ./libstdc++-v3/include/bits/stl_algo.h ./libstdc++-v3/include/bits/stl_function.h ./libstdc++-v3/include/bits/stl_uninitialized.h ./libstdc++-v3/include/bits/stl_stack.h ./libstdc++-v3/include/bits/stl_tempbuf.h ./libstdc++-v3/include/bits/stl_relops.h ./libstdc++-v3/include/bits/stl_bvector.h ./libstdc++-v3/include/bits/stl_multiset.h ./libstdc++-v3/include/bits/stl_iterator_base_funcs.h ./libstdc++-v3/include/bits/stl_algobase.h ./libstdc++-v3/include/bits/stl_queue.h ./libstdc++-v3/include/bits/stl_map.h ./libstdc++-v3/include/bits/stl_pair.h ./libstdc++-v3/include/bits/stl_numeric.h ./libstdc++-v3/include/bits/stl_iterator_base_types.h ./libstdc++-v3/include/bits/stl_raw_storage_iter.h ./libstdc++-v3/include/bits/stl_vector.h
复制代码

 

 

 

 

框架理解


概览图

 

 

阅读笔记

  • 提炼总结:概览

Ref: 《STL源码剖析》提炼总结:概览

STL是一个标准,只规定了STL的接口,内部实现没有要求。STL有许多实现版本,PJ STL(被Visual C++采用),RW STL等。

SGI STL版本注释丰富,结构清晰,可读性最强,同时它也被GCC采用,所以是最流行的版本。

注意,SGI STL并不是原封不动的被用于GCC,所以在GCC中使用STL可能会和SGI STL有一些微小的区别。

Goto: SGI STL DOCUMENTATION

 

STL分为六大组件:

    • 容器(container):常用数据结构,大致分为两类,序列容器,如vector,list,deque,关联容器,如set,map。在实现上,是类模板(class template)
    • 迭代器(iterator):一套访问容器的接口,行为类似于指针。它为不同算法提供的相对统一的容器访问方式,使得设计算法时无需关注过多关注数据。(“算法”指广义的算法,操作数据的逻辑代码都可认为是算法)
    • 算法(algorithm):提供一套常用的算法,如sort,search,copy,erase … 在实现上,可以认为是一种函数模板(function template)。
    • 配置器(allocator):为容器提供空间配置和释放,对象构造和析构的服务,也是一个class template。
    • 仿函数(functor):作为函数使用的对象,用于泛化算法中的操作。
    • 配接器(adapter):将一种容器修饰为功能不同的另一种容器,如以容器vector为基础,在其上实现stack,stack的行为也是一种容器。这就是一种配接器。除此之外,还有迭代器配接器和仿函数配接器。

 

  • 提炼总结:空间配置器(allocator)

Ref:《STL源码剖析》提炼总结:空间配置器(allocator)

使用自己编写的allocator来为vector分配空间:

#include <vector>

int main() { std::vector<int, my_alloc::allocator<int>> v; // Do something; return 0; }

一个最简单的allocator实现,它是符合STL标准的 

复制代码
#ifndef _MYALLOC_
#define _MYALLOC_

#include <new>
#include <cstddef>
#include <cstdlib>
#include <climits>
#include <iostream>

namespace my_alloc
{
    // allocate的实际实现,简单封装new,当无法获得内存时,报错并退出
    template <class T>
    inline T* _allocate(ptrdiff_t size, T*) {
        set_new_handler(0);
        T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
        if (tmp == 0) {
            cerr << "out of memory" << endl;
            exit(1);
        }
        return tmp;
    }

    // deallocate的实际实现,简单封装delete
    template <class T>
    inline void _deallocate(T* buffer) { ::operator delete(buffer); }

    // construct的实际实现,直接调用对象的构造函数
    template <class T1, class T2>
    inline void _construct(T1* p, const T2& value) { new(p) T1(value); }

    // destroy的实际实现,直接调用对象的析构函数
    template <class T>
    inline void _destroy(T* ptr) { ptr->~T(); }

    template <class T>
    class allocator {
    public:
        typedef T           value_type;
        typedef T*          pointer;
        typedef const T*    const_pointer;
        typedef T&          reference;
        typedef const T&    const_reference;
        typedef size_t      size_type;
        typedef ptrdiff_t   difference_type;

        // 构造函数
        allocator(){ return; }
        template <class U>
        allocator(const allocator<U>& c){}

        // rebind allocator of type U
        template <class U>
        struct rebind { typedef allocator<U> other; };

        // allocate,deallocate,construct和destroy函数均调用上面的实际实现
        // hint used for locality. ref.[Austern],p189
        pointer allocate(size_type n, const void* hint = 0) {
            return _allocate((difference_type)n, (pointer)0);
        }
        void deallocate(pointer p, size_type n) { _deallocate(p); }
        void construct(pointer p, const T& value) { _construct(p, value); }
        void destroy(pointer p) { _destroy(p); }

        pointer address(reference x) { return (pointer)&x; }
        const_pointer const_address(const_reference x) { return (const_pointer)&x; }

        size_type max_size() const { return size_type(UINT_MAX / sizeof(T)); }   
    };
} // end of namespace myalloc

#endif // _MYALLOC_
复制代码

 

  • C++之STL源码剖析:迭代器 Iterator

Ref: C++之STL源码剖析

OOP&GP

    • 面向对象:封装是基础,继承是手段,多态是目的。
    • 泛型编程:参数化类型是基础,模板是手段,通用是目的。
    • 面向对象的编程依赖运行时多态,泛型编程是编译时多态。

 

这里用List作为例子,数据结构是:

复制代码
  template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class list : protected _List_base<_Tp, _Alloc> { // concept requirements typedef typename _Alloc::value_type _Alloc_value_type; __glibcxx_class_requires(_Tp, _SGIAssignableConcept) __glibcxx_class_requires2(_Tp, _Alloc_value_type, _SameTypeConcept) typedef _List_base<_Tp, _Alloc> _Base; typedef typename _Base::_Tp_alloc_type _Tp_alloc_type; typedef typename _Base::_Node_alloc_type _Node_alloc_type; public: typedef _Tp value_type; typedef typename _Tp_alloc_type::pointer pointer; typedef typename _Tp_alloc_type::const_pointer const_pointer; typedef typename _Tp_alloc_type::reference reference; typedef typename _Tp_alloc_type::const_reference const_reference; typedef _List_iterator<_Tp> iterator; typedef _List_const_iterator<_Tp> const_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef _Alloc allocator_type;
... ...
复制代码

 

首先,节点如何定义?

复制代码
template <class T>
struct __list_node {
typedef
void* void_pointer; void_pointer prev; void_pointer next; T data; };
复制代码

 

其次,迭代器一般都放在容器中实现,针对某一类容器实现各自的迭代器.

vector<int>::iterator iter; // 定义一个正向迭代器

 

可见,::iterator的实现细节如下.

复制代码
template<class T, class Ref, class Ptr>
struct __list_iterator {
typedef __list_iterator
<T, T&, T*> iterator; typedef __list_iterator<T, Ref, Ptr> self; typedef __list_node<T>* link_type; __list_iterator(link_type x) : node(x) { } __list_iterator() { } __list_iterator(const iterator& x) : node(x.node) { } link_type node; bool operator==(const self& x) const { return node == x.node; } bool operator!=(const self& x) const { return node == x.node; } reference operator*() const { return (*node).data; } pointer operator->() const { return &(operator*()); } self& operator++() { node = (link_type)((*node).next); return *this; } self operator++(int) { self tmp = *this; ++*this; return tmp; } self& operator--() { node = (link_type)((*node).prev); return *this; } self operator--(int) { self tmp = *this; --*this; return tmp; } }
复制代码

 

 End.

posted @   郝壹贰叁  阅读(271)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示