C++ allocator类学习理解
前言
在学习STL中containers会发现C++ STL里定义了很多的容器(containers),每一个容器的第二个模板参数都是allocator类型,而且默认参数都是allocator。但是allocator到底是什么?有什么作用呢?
接下来就围绕着是什么和有什么作用来展开,其中最后补充一下如何去使用默认的allocator。
由于本人学习尚浅,各种blog和msdn学习了几天,依然还是不是特别理解。这是把自己的学习经验,进行一次梳理和记录。
What?
std::allocator template <class T> class allocator; // 默认分配器
默认分配器
所有的分配器都定义在 <memory> 头文件中,被用于标准库中的STL containers
如果标准容器中最后一个模板参数没有指定,那么就是allocator默认参数
对分配或释放存储的成员函数的调用将发生在一个总的顺序中,并且每个这样的释放将在下一个分配(如果有的话)之前发生。
主要成员函数
- address
函数原型:
pointer address (reference x) const noexcept;
const_pointer address ( const_referece x );
// reference => T& const_reference => const T&
返回x的地址
- allocate
函数原型:
pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
//hint:0 or 通过另外一个allocate获得的非零值且没有使用deallocate释放
//当 hint != 0 时,这个值可以作为一个提示,通过分配接近指定的新存储块来提高性能。相邻元素地址是一个不错的选择
pointer => T* const_pointer => const T* size_type => size_t
分配存储块
尝试分配n个T类型的存储空间,然后返回第一个元素的起始地址
只是分配空间,不构造对象
在标准默认allocator,存储块是使用 一次或多次 ::operator new 进行分配,如果他不能分配请求的存储空间,则抛出bad_alloc异常
- construct
原型函数:
template <class U, class... Args>
void construct(U* p, Args&&... args);在p指向的位置构建对象U,此时该函数不分配空间,pointer p是allocate分配后的起始地址
constructor将其参数转发给相应的构造函数构造U类型的对象,相当于 ::new ((void*) p) U(forward<Args> (args)...);
deallocate
原型函数:
void deallocate(pointer p, size_t n);
释放先前allocate分配的且没有被释放的存储空间
p:指向以前使用allocator :: allocate分配的存储块的指针。
n:在调用allocator :: allocate时为这个存储块分配的元素数量。在默认的allocator中,使用 ::operator delete进行释放
- destroy
原型函数:
template <class U>void destroy (U* p);
销毁p指向的对象,但是不会释放空间,也就意味着,这段空间依然可以使用
该函数使用U的析构函数,就像使用下面的代码一样:P->〜U();
- max_size
原型函数:
size_type max_size() const noexcept;返回最大可能分配的大小
How?
有关allocator的最重要的事实是它们只是为了一个目的:封装STL容器在内存管理上的低层细节。你不应该在自己的代码中直接调用 allocator 的成员函数,除非正在写一个自己的STL容器。你不应该试图使用allocator来实现operator new[];这不是allocator该做的。 如果你不确定是否需要使用allocator,那就不要用。
基本上很少有人会自定义一个allocator。一来,默认的allocator已经够用了;二来,确实不知道该怎么用。一般来说,我们没有必要重新定义一个allocator。自定义的方式主要是为了提高内存分配相关操作的性能。而STL提供的方式性能已经足够好了。
使用默认allocator
使用步骤:
由于allocator将内存空间的分配和对象的构建分离,故使用allocator分为以下几步:
- allocator与类绑定,因为allocator是一个泛型类
- allocate()申请指定大小空间
- construct()构建对象,其参数为可变参数,所以可以选择匹配的构造函数
- 使用,与其它指针使用无异
- destroy()析构对象,此时空间还是可以使用
- deallocate()回收空间
请认真遵守这个顺序使用,不然会无法预料的异常
( 下面该程序也可以解决无默认参数来构造对象数组的问题)
//#include "CAnimal.h"
#include <memory>
#include <iostream> using namespace std; class Animal
{
public:
#if 1 //即使为0,没有默认构造也是可以,
Animal() : num()
{
cout << "Animal constructor default" << endl;
}
#endif
Animal(int _num) : num(_num)
{
cout << "Animal constructor param" << endl;
} ~Animal()
{
cout << "Animal destructor" << endl;
} void show()
{
cout << this->num << endl;
} private:
int num;
}; int main()
{
allocator<Animal> alloc; //1.
Animal *a = alloc.allocate(); //2. //3.
alloc.construct(a, );
alloc.construct(a + );
alloc.construct(a + , );
alloc.construct(a + );
alloc.construct(a + , ); //4.
a->show();
(a + )->show();
(a + )->show();
(a + )->show();
(a + )->show(); //5.
for (int i = ; i < ; i++)
{
alloc.destroy(a + i);
}
//对象销毁之后还可以继续构建,因为构建和内存的分配是分离的
//6.
alloc.deallocate(a, ); cin.get();
return ;
}
通过运行结果可以看出,无论是否有默认构造,allocator会选择出最匹配的构造函数(重载)
结语:由于现在自己木有工作经验和项目经验,实在对这个allocator的使用,懵懵懂懂,在使用STL containers时,也没有看见自定义的Allocator,现在只能简单学习了解,以便以后工作捡起来不那么难或者在看大神的代码的时候不在那么懵逼。。。
好吧!就这样吧。。。
C++ allocator类学习理解的更多相关文章
- MLT的学习理解
MLT的学习理解 MLT是一个开源的多媒体库,我们的音视频编辑工具,是使用它作为底层支持,某司的'快剪辑'pc版和安卓版,也是用的它. MLT简介 它的GitHub地址,这个库比较老了,现在只有一个作 ...
- 菜鸟之路——机器学习之SVM分类器学习理解以及Python实现
SVM分类器里面的东西好多呀,碾压前两个.怪不得称之为深度学习出现之前表现最好的算法. 今天学到的也应该只是冰山一角,懂了SVM的一些原理.还得继续深入学习理解呢. 一些关键词: 超平面(hyper ...
- [BS-18] 对OC中不可变类的理解
对OC中不可变类的理解 OC中存在很多不可变的类(如NSString,NSAttributedString,NSArray,NSDictionary,NSSet等),用它们创建的对象存在于堆内存中,但 ...
- C++ Primer : 第十二章 : 动态内存之allocator类
标准库allocator类定义在头文件 <memory>中.它帮助我们将内存分配和构造分离开来,它分配的内存是原始的.未构造的. 类似vector,allocator也是一个模板类,我们在 ...
- 【转】Date类学习总结(Calendar Date 字符串 相互转换 格式化)
原文网址:http://www.blogjava.net/jerry-zhaoj/archive/2008/10/08/233228.html Date类学习总结 1.计算某一月份的最大天数 Cale ...
- C++--allocator类的使用
C++为我们提供了安全的内存空间申请方式与释放方式,可是new与delete表达式却是把空间的分配回收与对象的构建销毁紧紧的关联在一起.实际上,作为与C语言兼容的语言,C++也为我们提供了更加底层的内 ...
- 全面学习理解TLB(Translation Look-aside Buffer)地址变换高速缓存
全面学习理解TLB(Translation Look-aside Buffer)地址变换高速缓存 前言: 本文学习思路是:存在缘由 --> 存在好处 --> 定义性质 --> 具 ...
- 对Java中properties类的理解
转载于:https://www.cnblogs.com/bakari/p/3562244.html 一.Java Properties类 Java中有个比较重要的类Properties(Java.ut ...
- AtomicInteger类的理解与使用
AtomicInteger类的理解与使用 首先看两段代码,一段是Integer的,一段是AtomicInteger的,为以下: public class Sample1 { private stati ...
随机推荐
- Java IO(2)
关于流的概念 Java 由流来完成具体的IO操作,虽然面对的是不同的外设(网络.鼠标.键盘)IO流使用与全部的外设,在底层Java已经将具体与物理设备交互的细节都处理好了. 流的分类: 从功能上 输入 ...
- android handler 调用原理
1,调度原理 andriod提供了Handler 和 Looper 来满足线程间的通信.Handler先进先出原则.Looper类用来管理特定线程内对象之间的消息交换(MessageExchange) ...
- phpcms批量更新内容页只更新一点就返回问题
phpcms批量更新内容页只更新一点就返回问题 给caches目录增加写入权限
- Hibernate使用时需要注意的几个小问题
今天晚上玩了一下JDBC连接数据库,之后又利用Hibernate进行了数据库的访问,感觉利用Hibernate对数据库访问在文件配置好了之后确实更加简单快捷. 但是在操作的过程中也有一些细节需要注意一 ...
- BZOJ 3931 (网络流+最短路)
题面 传送门 分析 考虑网络流 注意到数据包走的是最短路,所以我们只需要考虑在最短路上的边 由于最短路可能有多条,我们先跑一遍Dijkstra,然后再\(O(m)\) 遍历每条边(u,v,w) 如果d ...
- Codeforces - 1191F - Tokitsukaze and Strange Rectangle - 组合数学 - 扫描线
https://codeforces.com/contest/1191/problem/F 看了一下题解的思路,感觉除了最后一段以外没什么启发. 首先离散化x加快速度,免得搞多一个log.其实y不需要 ...
- Jmeter JAVA请求入门
一.Jmeter完成一个java请求实现方法 两种实现方式: 实现JavaSamplerClient接口 继承AbstractJavaSamplerClient抽象类 二.使用AbstractJava ...
- StackExchange.Redis 使用LuaScript脚本模糊查询hash
原文:StackExchange.Redis 使用LuaScript脚本模糊查询hash 获取redis连接 public class RedisHelper { private static rea ...
- Spring Data Redis实战之提供RedisTemplate
参考: http://www.cnblogs.com/edwinchen/p/3816938.html 本项目创建的是Maven项目 一.pom.xml引入dependencies <depen ...
- 基于TensorFlow Object Detection API进行迁移学习训练自己的人脸检测模型(二)
前言 已完成数据预处理工作,具体参照: 基于TensorFlow Object Detection API进行迁移学习训练自己的人脸检测模型(一) 设置配置文件 新建目录face_faster_rcn ...