首页 > 代码库 > STL内存分配

STL内存分配

STL内存创建

Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu  转载请标明来源 

 

1.      Stl内存创建基类模板__malloc_alloc_template

STL的常用的内存创建参考文件: stl_alloc.h,文件中定义了__malloc_alloc_template模板库,创建与释放使用C方法mallocfreerealloc,模板库里面主要对外提供了函数:

allocate: 分配内存

deallocate: 释放内存

reallocate: 重新分配内存

__set_malloc_handler: 设置异常处理函数

template <int __inst>

class __malloc_alloc_template {

 

private:

 

  static void* _S_oom_malloc(size_t);

  static void* _S_oom_realloc(void*, size_t);

 

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG

  static void (* __malloc_alloc_oom_handler)();

#endif

 

public:

 

  static void* allocate(size_t __n)

  {

    void* __result = malloc(__n);

    if (0 == __result) __result = _S_oom_malloc(__n);

    return __result;

  }

 

  static void deallocate(void* __p, size_t /* __n */)

  {

    free(__p);

  }

 

  static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz)

  {

    void* __result = realloc(__p, __new_sz);

    if (0 == __result) __result = _S_oom_realloc(__p, __new_sz);

    return __result;

  }

 

  static void (* __set_malloc_handler(void (*__f)()))()

  {

    void (* __old)() = __malloc_alloc_oom_handler;

    __malloc_alloc_oom_handler = __f;

    return(__old);

  }

 

};

 

1.   内存分配与释放

使用mallocrealloc分配内存,对于分配内存异常的处理,模板库中交给内部的这两个静态方法:

_S_oom_malloc

_S_oom_ realloc

 

使用free释放内存,对于释放内存来说,是无异常处理的,直接调用free指针,传入的size_t未使用。

 

2.   分配异常处理

分配内存的异常处理方法,参考_S_oom_malloc/_S_oom_realloc中的实现

在实现中或者是通过抛出异常,或者是通过执行约定的处理函数(如内存整理函数),然后继续申请内存。

在下面的函数中,涉及了函数指针:

__malloc_alloc_oom_handler

这个函数指定方法__malloc_alloc_template ::__set_malloc_handler

 

如果这个函数未指定的话,调用异常__THROW_BAD_ALLOC处理

a.   C++下,抛出std::bad_alloc(),

b.   C下,向标准输出中打印并终止程序: fprintf(stderr, "out of memory\n"); exit(1)

 

如果这个函数指定的话,指行这个函数(例如内存整理函数),然后再次申请内存,直到成功申请到后返回申请到的内存地址:

__my_malloc_handler = __malloc_alloc_oom_handler;

(*__my_malloc_handler)();

__result = malloc(__n);

if (__result) return(__result);

 

#ifndef __THROW_BAD_ALLOC

#  if defined(__STL_NO_BAD_ALLOC) || !defined(__STL_USE_EXCEPTIONS)

#    include <stdio.h>

#    include <stdlib.h>

#    define __THROW_BAD_ALLOC fprintf(stderr, "out of memory\n"); exit(1)

#  else /* Standard conforming out-of-memory handling */

#    include <new>

#    define __THROW_BAD_ALLOC throw std::bad_alloc()

#  endif

#endif

 

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG

template <int __inst>

void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0;

#endif

 

template <int __inst>

void*

__malloc_alloc_template<__inst>::_S_oom_malloc(size_t __n)

{

    void (* __my_malloc_handler)();

    void* __result;

 

    for (;;) {

        __my_malloc_handler = __malloc_alloc_oom_handler;

        if (0 == __my_malloc_handler) { __THROW_BAD_ALLOC; }

        (*__my_malloc_handler)();

        __result = malloc(__n);

        if (__result) return(__result);

    }

}

 

template <int __inst>

void* __malloc_alloc_template<__inst>::_S_oom_realloc(void* __p, size_t __n)

{

    void (* __my_malloc_handler)();

    void* __result;

 

    for (;;) {

        __my_malloc_handler = __malloc_alloc_oom_handler;

        if (0 == __my_malloc_handler) { __THROW_BAD_ALLOC; }

        (*__my_malloc_handler)();

        __result = realloc(__p, __n);

        if (__result) return(__result);

    }

}

 

3.   封装的几组分配方式

a.   Simple_alloc,附加了检查0/NULL的操作

 

template<class _Tp, class _Alloc>

class simple_alloc {

 

public:

    static _Tp* allocate(size_t __n)

      { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); }

    static _Tp* allocate(void)

      { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); }

    static void deallocate(_Tp* __p, size_t __n)

      { if (0 != __n) _Alloc::deallocate(__p, __n * sizeof (_Tp)); }

    static void deallocate(_Tp* __p)

      { _Alloc::deallocate(__p, sizeof (_Tp)); }

};

 

b.   debug_alloc每次分配时,多附加8字节的空间,用于存储当前分配的size大小。

// Allocator adaptor to check size arguments for debugging.

// Reports errors using assert.  Checking can be disabled with

// NDEBUG, but it‘s far better to just use the underlying allocator

// instead when no checking is desired.

// There is some evidence that this can confuse Purify.

template <class _Alloc>

class debug_alloc {

 

private:

 

  enum {_S_extra = 8};  // Size of space used to store size.  Note

                        // that this must be large enough to preserve

                        // alignment.

 

public:

 

  static void* allocate(size_t __n)

  {

    char* __result = (char*)_Alloc::allocate(__n + (int) _S_extra);

    *(size_t*)__result = __n;

    return __result + (int) _S_extra;

  }

 

  static void deallocate(void* __p, size_t __n)

  {

    char* __real_p = (char*)__p - (int) _S_extra;

    assert(*(size_t*)__real_p == __n);

    _Alloc::deallocate(__real_p, __n + (int) _S_extra);

  }

 

  static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz)

  {

    char* __real_p = (char*)__p - (int) _S_extra;

    assert(*(size_t*)__real_p == __old_sz);

    char* __result = (char*)

      _Alloc::reallocate(__real_p, __old_sz + (int) _S_extra,

                                   __new_sz + (int) _S_extra);

    *(size_t*)__result = __new_sz;

    return __result + (int) _S_extra;

  }

 

};

 

 

4.   内存分配信息存储类allocator

 

// This implements allocators as specified in the C++ standard. 

//

// Note that standard-conforming allocators use many language features

// that are not yet widely implemented.  In particular, they rely on

// member templates, partial specialization, partial ordering of function

// templates, the typename keyword, and the use of the template keyword

// to refer to a template member of a dependent type.

 

#ifdef __STL_USE_STD_ALLOCATORS

 

template <class _Tp>

class allocator {

  typedef alloc _Alloc;          // The underlying allocator.

public:

  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;

 

  template <class _Tp1> struct rebind {

    typedef allocator<_Tp1> other;

  };

 

  allocator() __STL_NOTHROW {}

  allocator(const allocator&) __STL_NOTHROW {}

  template <class _Tp1> allocator(const allocator<_Tp1>&) __STL_NOTHROW {}

  ~allocator() __STL_NOTHROW {}

 

  pointer address(reference __x) const { return &__x; }

  const_pointer address(const_reference __x) const { return &__x; }

 

  // __n is permitted to be 0.  The C++ standard says nothing about what

  // the return value is when __n == 0.

  _Tp* allocate(size_type __n, const void* = 0) {

    return __n != 0 ? static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp)))

                    : 0;

  }

 

  // __p is not permitted to be a null pointer.

  void deallocate(pointer __p, size_type __n)

    { _Alloc::deallocate(__p, __n * sizeof(_Tp)); }

 

  size_type max_size() const __STL_NOTHROW

    { return size_t(-1) / sizeof(_Tp); }

 

  void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }

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

};

 

 

STL内存分配