STL内存分配

STL内存创建

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

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

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

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.   内存分配与释放

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

_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(); }

};

时间: 2024-12-28 09:18:24

STL内存分配的相关文章

c++ stl 内存配置器

在STL中,Memory Allocator 处于最底层的位置,为一切的 Container 提供存储服务,是一切其他组件的基石.对于一般使用 STL 的用户而言,Allocator 是不可见的,如果需要对 STL 进行扩展,如编写自定义的容器,就需要调用 Allocator 的内存分配函数进行空间配置. 在C++中,一个对象的内存配置和释放一般都包含两个步骤,对于内存的配置,首先是调用operator new来配置内存,然后调用对象的类的构造函数进行初始化:而对于内存释放,首先是调用析构函数,

STL六大组件之——分配器(内存分配,好深奥的东西)

SGI设计了双层级配置器,第一级配置器直接使用malloc()和free(),第二级配置器则视情况采用不同的策略:当配置区块超过128bytes时,视之为“足够大”,便调用第一级配置器:当配置区小于128bytes时,视之为“过小”,为了降低额外负担,便采用复杂的memory pool 整理方式,而不再求助于第一级配置器.整个设计究竟只开放第一级配置器,取决于_USE_MALLOC是否被定义: 1 #ifdef __USE_MALLOC 2 ... 3 typedef __malloc_allo

解析STL中典型的内存分配

1 vector 在C++中使用vector应该是非常频繁的,但是你是否知道vector在计算内存分配是如何么? 在c++中vector是非常类似数组,但是他比数组更加灵活,这就表现在他的大小是可以自动分配的,就是当你的数据量增大的时候,自动的为你分配空间,当你的分配的大小不够的时候,他就会在分配的内存后边增加2倍大小的空间, vector增加的空间是连续的,因此这个就涉及到了,当你在后边的空间不够的时候,那么计算机就会把你的数据copy一份空间更大的地方来给你分配足够的空间,这,就给计算机带来

STL内存管理器的分配策略

STL提供了很多泛型容器,如vector,list和map.程序员在使用这些容器时只需关心何时往容器内塞对象,而不用关心如何管理内存,需要用多少内存,这些STL容器极大地方便了C++程序的编写.例如可以通过以下语句创建一个vector,它实际上是一个按需增长的动态数组,其每个元素的类型为int整型: stl::vector<int> array; 拥有这样一个动态数组后,用户只需要调用push_back方法往里面添加对象,而不需要考虑需要多少内存: array.push_back(10); a

STL容器的内存分配

这篇文章参考的是侯捷的<STL源码剖析>,所以主要介绍的是SGI STL实现版本,这个版本也是g++自带的版本,另外有J.Plauger实现版本对应的是cl自带的版本,他们都是基于HP实现的版本,有兴趣可以翻翻最新的源码头文件开始处有声明. /* * * Copyright (c) 1994 * Hewlett-Packard Company(这里) * * Permission to use, copy, modify, distribute and sell this software *

Effective STL: 使用reserve来避免不必要的内存分配

使用reserve来避免不必要的内存分配 当确切或大约知道有多少元素将最后出现在容器中 vector<int> v; // 如果此处不用reserve来先出发内存分配,下面的循环会出现多次内存的重新分配(涉及到分配.回收.拷贝.析构等耗费昂贵的动作) v.reserve(1000); for (int i = 1; i <= 1000; ++i) { v.push_back(i); } 保留你可能需要的最大的空间,然后,一旦你添加完全部数据,修整掉任何多余的容量(可以考虑用swap来修整

SGI STL内存配置器存在内存泄漏吗?

阅读了SGI的源码后对STL很是膜拜,很高质量的源码,从中学到了很多.温故而知新!下文中所有STL如无特殊说明均指SGI版本实现. STL 内存配置器 STL对内存管理最核心部分我觉得是其将C++对象创建过程分解为构造.析构和内存分配.释放两类操作分离开来!摆脱了对频繁调用new或malloc函数想操作系统申请空间而造成的低效.其中析构操作时对具有non-trival.trival 析构函数的class区别对待也提高了效率.SGI 的两级配置器结构属于锦上添花. STL内存配置器有没有内存泄漏?

QVector的内存分配策略

我们都知道 STL std::vector 作为动态数组在所分配的内存被填满时.假设继续加入数据,std::vector 会另外申请一个大小当前容量两倍的区域(假设 n > size 则申请 n+当前容量 的空间).然后把当前内容复制到新的内存,以达到动态扩容的效果: size_type _M_check_len(size_type __n, const char* __s) const { if (max_size() - size() < __n) __throw_length_error

【转载】C++内存分配

原文:C++内存分配 内存泄露相信对C++程序员来说都不陌生.解决内存泄露的方案多种多样,大部分方案以追踪检测为主,这种方法实现起来容易,使用方便,也比较安全. 首先我们要确定这个模块的主要功能: 能追踪内存的分配和释放过程. 要能显示内存分配的相关信息,比如内存块大小,代码所在文件所在行等. 在发现内存泄露时及时给出相关信息. 能正确处理一些异常情况,比如内存不足,对象初始化失败等等. 是线程安全的.[*这个还没有实现] 有了一些基本功能需求,我们需要考虑每种功能怎么去实现.首先,我们可以通过