STL源码解析阅读理解:Allocator

前言
这本书去年就有看过一点,但是那个时候读源码读的太痛苦,遂放弃了一段时间,后来断断续续又看了点,但是每次碰到allocator部分的知识依旧是云里雾里。现在决定从头开始再看一遍。
以下内容是我阅读 侯捷《STL源码剖析》 这本书的笔记。如果有理解有误的地方还望各位大佬能够不吝指出。

在我们正式开始介绍Allcoator(空间配置器)之前先想一个问题。我们为什么要有空间配置器?这个问题我知道很简单,顾名思义,当然是为了分配空间啦。那分配空间的目的能?那当然是为了存储数据啦。就像书中所言” 整个STL的操作对象(所有数值)都存放在容器之内,而容器一定需要配置空间以存放资料

这里将allocator定义为空间配置器而不是内存配置器的原因:因为空间不一定是内存,空间也可以是磁盘或其它辅助存储介质。【书中原话】

学习大纲

学习大纲

SGI 空间配置器的种类及区别

SGI的空间配置器有两种:

  1. SGI标准的空间配置器,std::allocator
  2. SGI特殊的空间配置器,std::alloc

它们两者之间的区别:

  1. 它们的底层实现不同。std::allocator中的底层是用operator new和operator delete实现的空间配置和释放;而std::alloc中使用的则是malloc和free完成的配置和释放
  2. std::allocator中,内存配置和对象构造封装在allocate函数中一步完成的(一会介绍原因),内存释放和对象析构也是封装在deallocate函数中一步完成的。而std::alloc中,内存的配置与释放和对象的构造与析构都是使用单独的函数实现的。

::operator new和::operator delete的操作步骤

我们平时调用的new/delete实际上就是::operator new和::operator delete这两个函数。
我们来看下面的语句:

A *a = new A;	// 分配内存,然后构造对象
delete a;		// 将对象析构,然后释放内存

这个语句等号右边的部分(new A)中实际上进行了两个操作:

  1. 调用::operator new分配内存;
  2. 调用A::A()构造对象。

同理,对于delete a;而言也包含两个操作

  1. 调用A::~A()将对象析构;
  2. 调用::operator delete释放内存。

这也就为什么我们说在std::allocator中,内存分配和对象构造是被封装在同一个函数中的原因了。因为它的allocate函数的底层实现就是通过operator new来完成的,人家operator new本身就包含了内存分配和对象构造啦,你总不能把人家强行扯开吧~

下面分别介绍std::allocator和std::alloc。

SGI标准的空间配置器,std::allocator

allocate()

template<class T>
inline T* allocate(ptrdiff_t, size. T*){
   
	set_new_handler(0);		// 处理内存不足,这里被设置为0,表示遇到内存不足情况的时候直接抛出bad_alloc异常
	T* tmp = (T*) (::operator new((size_t)(size * sizeof(T))));	//直接调用new分配内存,并且构造对象
	// 当内存分配失败时会打印out of memory,并且强制退出
	if (tmp == 0){
   
		cerr << "out of memory" << endl;
		exit(1);
	}
	return tmp;
}

deallocate()

template<class T>
inline void deallocate(T* buffer){
   
	::opertator delete(buffer);		// 直接调用delete析构对象,并释放内存
}

SGI特殊的空间配置器,std::alloc

该配置器中对象的构造与析构放在头文件:#incldue<stl_construct.h>
该配置器中空间的配置与释放放在头文件:#incldue<stl_alloc.h>

该配置器的空间分配又分为两种:

  1. 一级空间配置器
  2. 二级空间配置器

对象的构造和析构(待补充)

construct()

需要用到头文件 #include<new.h>中的placement new

#includde <new.h>

// 构造对象
template<class T1, class T2>
inline void construct(T1 *p, T2& value){
   
	new(p) T1(value);     // 调用T1::T1()构造函数,并将初始值设定到指针所指的空间上,这个由placement new完成
}

destroy()

destroy()实现析构对象。包括两个版本:

  1. 仅接受一个指针,也就是仅析构一个对象;
  2. 接受两个迭代器,析构这两个迭代器之间的值,一般是[first, last),左闭右开。
// 第一个版本的destroy()
template <class T>
inline void destroy(T* pointer){
   
	pointer->~T();
}


// 第二个版本的destory()
template < class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last){
   
// 两个参数,[first, last}范围内的对象析构掉
	__destroy(first, last, value_type(first));	 // 最后一个参数主要是为了判断该迭代器的类型
}

// 判断元素的数值类型是否由trivial destructor
template < class ForwardIterator, class T?
inline void __destroy(ForwardIterator first, ForwardIterator last, T*){
   
	typedef typename __type_traits<T>::
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值