STL源码剖析---根据最新版本的g++4.9.0(支持C++11)的修订(1)空间配置器


STL源码剖析---根据最新版本的g++4.9.0(支持C++11)的修订(1)空间配置器

  源码剖析采用的G++版本为2.91.57版本,是比较老的版本与最新版本4.9.0有某些方面的差别。现在我针对最新版本做一个分析。我下载了最新的gcc-4.9.0的包作为观察对象:

  我们#include <>时的头文件放在:gcc-4.9.0/libstdc++-v3/include/std;例如vector。

  真正的实现文件放在:gcc-4.9.0/libstdc++-v3/include/bits;例如:stl_vector,注意前面的stl_。

  最后要说的是:技术是不断进步,不断发展变化的。两个G++版本存在差别,4.9.0版本已经很新了,但是也不能保证后来的g++版本相对现在的就不会变化,而且可以肯定的说后来的肯定会有所变化,所以我们要用发展变化的眼光看待问题,做技术的也是同样的道理。

1. 空间配配器allocator

  allocator作为C++标准的空间配置,提供了必要的空间分配能力。

2. 新版的SGI真的用std::alloc

  源码剖析说SGI STL用alloc作为配置器,从未使用allocator。但是在新版本中就不一样了,使用的是标准的std::allocator。

#include <iostream>
#include <memory>
#include <vector>

using std::vector;
using std::cout;
using std::endl;
using std::allocator;

int main(void)
{
    vector<int, allocator<int>> ivec;

    ivec.push_back(3);
    cout << ivec[0] << endl;

    return 0;
}

编译:

[root@www 桌面]# g++ allocator.cc -std=c++0x
[root@www 桌面]# ./a.out
3


  结论:新版gcc 可以使用std::allocator。可以试下std::alloc,发现无法编译成功。

  查找vector定义发现默认配置器未std::allocator:

  template<typename _Tp, typename _Alloc = std::allocator<_Tp> >

  class vector : protected _Vector_base<_Tp, _Alloc>

3. SGI <memory>

  配置器定义于<memory>中,SGI<memory>中包含:

  #include <bits/allocator.h> //不是alloc.h,定义了内存空间的配置allocate(), 释放deallocate()
  #include <bits/stl_construct.h>//负责对象昂内容的构造construct, 析构destroy()

  #include <bits/stl_uninitialized.h>//定义了全局函数,用来fill或copy大块内存

4. c++ 提供的基本内存分配函数

4.1. 最基本的operator new, operator delete

在int *ip = new int发生了什么?

(1)调用名为opreator new的标准库函数分配足够大小的原始的未初始化的内存,以保存指定类型的对象。

(2)运行该类型的构造函数,用指定初始化式构造对象。

(3)返回指向新分配的并构造的对象的指针。

在delete ip;时发生什么?

(1)对ip指向的对象运行适当的析构函数。

(2)调用operator delete的标准库函数释放该对象所用内存。

4.2. operatro new;operator delete;

//operator new用于分配原始内存空间。

//类似C语言的malloc(size_t); C++ alloc.allocate(size_t);

void *operator new(size_t);

void *operaotr new[](size_t);

//operator delete用于回收对象所占的内存。

//类似C语言的free();C+++ alloc.deallocate();

void *operator delete(void*);

void *operator delete[](void*);

4.3. place new: 初始化原始内存空间

place new 定位new: 在已分配的原始内存空间中初始化一个对象。

new(place_address) type;

new(place_address) type(initlist-list);

相对于alloc.construct(pos, val);更灵活,可以使用任意构造函数。

而construct只能用copy constructor,对于有些类效率可能底,也有可能不支持,就只能用place new。

5. STL提供的全局的算法

定义在<bits/stl_uninitialized.h>: uninitialized_copy, uninitialized_fill, uninitialized_fill_n

5.1. uninitialized_copy:POD类型调用STL算法copy(first, last, result), 非POD类型调用construct(pos, value),char*和wchar*调用memmove

template <class InputIterator, class ForwardIterato>

ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwareIterator result);

将内存的配置与对象的构造行为分离开来。若,[result, result + (last - first))的每一个迭代器iter都指向未初始化区域,该函数都会调用

construct(&*(result + (iter - first)), *iter),产生*iter的复制品,放置于输出范围的相对位置上。

对于容器的全区间构造函数,可以使用uninitialized_copy()在该容器的内存上构造函数。

该函数具有commit or rollback语义,要么构造出所有元素,要么(当有任何copy construct失败时),不构造任何东西。

5.2 uninitialized_fill:POD类型调用STL算法fill(first, last, x), 非POD类型调用construct(pos, value)

template <class Forwarditerator, class T>

void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T&x);

用于在未初始化的内存上构造对象, 会在[first, last)范围内产生x的复制品。即会对范围内的每个迭代器调用construct(&*i, x), 在i所指处产生x的复制品。

同样的也支持commit or rollback。

5.3. uninitialized_fill_n:POD类型调用STL算法fill_n(first, n, x), 非POD类型调用construct(pos, value)

template <class ForwardIterator, class Size, class T>

ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T &x);

与上面两个基本相同,从first开始位置,构造n个x。

6. allocator: 是STL提供的一个封装类,对operator new, operator delete和place new, ~T()的封装,方便分配内存。

template<typename _Tp> 
class allocator { public:   //各种type的设计:
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef _Tp* pointer;
  typedef const _Tp* const_pointer;
  typedef _Tp& reference;
  typedef const _Tp&
const_reference;
  typedef _Tp value_type;
  //construct, copy construct, deconstruct
  allocator() throw() { }
  allocator(const allocator& __a) throw() { }
  template<typename _Tp1>
  allocator(const allocator<_Tp1>&) throw() { }
  ~allocator() throw() { }

  //必须的成员
  template
<typename _Tp1>   struct rebind
  {
    typedef allocator
<_Tp1> other;
  };

  pointer address(reference __x) const noexcept
  {
    return std::__addressof(__x);(return (pointer)&x);
  }
  
  const_pointer address(const_reference __x)
const noexcept
  {
    return std::__addressof(__x);(return (const_pointer)&x);
  }

  pointer allocate(size_type __n,
const void* = 0) { if (__n > this->max_size()) std::__throw_bad_alloc(); return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); }
  
  void
deallocate(pointer __p, size_type)
  {
    ::
operator delete(__p);
  }
  size_type max_size()
const noexcept
  {
    return size_t(-1) / sizeof(_Tp);
  }

#if __cplusplus >= 201103L

  template<typename _Up, typename... _Args> void construct(_Up* __p, _Args&&... __args) {
    ::
new((void *)__p) _Up(std::forward<_Args>(__args)...);
  }
  template
<typename _Up>   void destroy(_Up* __p) { __p->~_Up(); } #else void construct(pointer __p, const _Tp& __val) {
    ::
new((void *)__p) _Tp(__val);
  }

  void
destroy(pointer __p) { __p->~_Tp(); } #endif

}; //allocator<void> specialization.
//void的完全特化版本
template<>

class allocator<void> {
public:
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef void* pointer;
  typedef const void* const_pointer;
  typedef void value_type;

  template<typename _Tp1>
  struct rebind
  {
    typedef allocator<_Tp1> other;
  };

}

7. 总结

  (1) 原始内存空间分配:operator new 或者 allocator.allocator();

  (2)原始内存空间初始化对象:place new 或者 allocator.construct(); uninitiated系列函数。

  (3) 清理对象:~T() 或者 allocator.destroy()。

  (4)内存空间的回收:operator delete 或者 allocator.deallocator();

  完成以上几个步骤的函数:new, delete。

  

优质内容筛选与推荐>>
1、杭电2000
2、Trie树
3、结队开发项目——基于Android的无线点餐系统——NABC模型
4、显示天气代码
5、python tar 打包


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn