STL初探——第一级配置器 __malloc_alloc_template的学习心得

  在第一级配置器中,一开始就定义了内存分配出错的宏接口,如下:

#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
"); exit(1)
#  else /* Standard conforming out-of-memory handling */
#    include <new>
#    define __THROW_BAD_ALLOC throw std::bad_alloc()
#  endif
#endif

  先弄清楚第一级配置器如何工作,注意没有template型别参数,因为我们只是分配空间,并不进行对象的构造,至于非型别参数 "__inst" ,就没怎么派上用场,如下:

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); //分配的内存无法满足需求时,调用_S_oom_malloc()函数
    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;
  }
  //你可以通过该函数指定自己的 out-of-memory handler
  static void (* __set_malloc_handler(void (*__f)()))()
  {
    void (* __old)() = __malloc_alloc_oom_handler;
    __malloc_alloc_oom_handler = __f;
    return(__old);
  }
};
// malloc_alloc out-of-memory handling #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 (;;) {                                //和_S_oom_realloc类似                         __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); } }

  第一级配置器以 malloc()、free()、realloc()等 C 函数执行实际的内存配置、释放、重配置操作,并实现出类似 C++ new-handler 的机制,不过并不能直接使用 C++ new-handler 机制, 因为其并非使用 ::operator new 来配置内存。

  C++ new-handler 机制是,可以要求系统在配置需求无法被满足时,调用你所指定的函数。一旦 ::operator new 无法完成任务,在丢出 std::bad_alloc 异常状态之前,会先调用由客端指定的处理例程,该处理例程通常被称为new-handler。

  《effective C++ handler》 中介绍了 new-handler 的内存不足处理模式,详情见下篇。

  SGI 以malloc 而非 ::operator new 来配置内存,原因是C++并未提供相应于 realloc() 的内存配置操作,当然不排除还有些历史因素。因此,SGI 不能使用 C++ 的 set_new_handler() ,必需仿真一个类似类似的 set_new_handler().

  SGI 第一级配置器 allocate() 和 realloc() 都是在调用 malloc() 和 realloc() 不成功后,改调用 oom_malloc() 和 oom_realloc()。后两者都有死循环,不断调用 "内存不足处理例程" ,期望在某次调用的时候,能够得到充足的内存分配而完成任务。但如果“内存不足处理例程”并没有被客端设定, oom_malloc() 和 oom_realloc() 便会直接调用 __THROW_BAD_ALLOC,丢出 bad_alloc 异常信息,或利用 exit(1)终止程序。

  

既然选择了远方,便只顾风雨兼程
原文地址:https://www.cnblogs.com/Forever-Road/p/6808442.html