源码阅读笔记 - 2 std::vector (2) 关于Allocator Aware Container特性
所有的STL容器,都保存一个或默认,或由用户提供的allocator的实例,用来提供对象内存分配和构造的方法(除了std::array),这样的容器,被称作Allocator Aware Container。早期的STL,设计的尚不完善,各种实现之间不能相互兼容,这一点在侯捷的《STL源码剖析》中有提到:有些STL的实现无法兼容标准的allocator实现,因为他们使用了更为复杂的二级配置器。而在我昨天阅读完vector和其处理allocator拷贝、移动和交换问题的源码后,发现这种问题在如今的STL中已经不再存在,allocator和容器的标准本身提供了选项,用于更加复杂的分配器的拷贝操作。
每一个Allocator Aware Container在拷贝构造(copy constuction)的时候,都会调用被拷贝对象的std::allocator_traits<TAllocator>::select_on_container_copy_construction()函数,这是一个静态函数,会通过编译时重载决议,按情况拷贝,或者直接返回被拷贝对象的allocator。
函数内部通过调用allocator的成员select_on_container_copy_construction()函数,如果没有,就直接返回容器本体。
同时,容器的设计者也应该在容器拷贝的时候要么调用静态的propagate_on_container_copy_assignment,要么直接调用成员propagate_on_container_copy_assignemnt,获取被拷贝容器的allocator副本,避免出现直接拷贝容器的bug。
每一个std::allocator_traits<Tallocator>都拥有三个别名类型:propagate_on_container_copy_assignment, propagate_on_container_move_assignment 和 propagate_on_container_swap,他们都是true_type或false_type的别名,这三个属性除非用户自定义,否则默认是false_type,也即allocator在容器拷贝、移动或交换的时候不能直接进行allocator所分配的内存的所有权的转移
容器在移动赋值(move assignment)的时候需要考虑如下情况,来正确操作容器的allocator:
- propagate_on_container_move_assignemnt 为 true_type
 - propagate_on_container_move_assignemnt 为 false_type,但两个allocator相等
 - propagete_on_container_move_assignment 为 false_type,两个allocator不等
 
第{1}和{2, 3}能通过编译时重载决议区分,而{2},{3}需要运行时通过if判断。
第一种情况下,lhs需要先用他自己的allocator释放掉它自己分配的东西,然后rhs的allocator的所有权转移(move),最后是memory的所有权从rhs转移到lhs。
第二种情况下,可以重复第一种情况,但是allocator本身不需要交换所有权
第三种情况,无法执行内存级别的移动,只能进行对象级别的移动
对于移动构造,直接把allocator move过来,然后转移memory的所有权。
对于拷贝赋值(copy assignment),需要运行时判断容器的propagate_on_copy_assignement trait,如果为true,并且两个容器不相等,那么lhs的容器应该先析构所有内存,再拷贝allocator,最后执行对象的拷贝。
有了上面的设计,使用多级分配器的容器间的拷贝变得有可能了,如果有人想要给每一个allocator使用一个独立的内存池,那么显然内存池之间的对象所有权不是随随便便拷贝个指针就能转移的,这时也许需要把三个tag都设置为false,让allocator的operator==重载不直接返回true,使得资源的转移按照自己期望的方式进行。如果自定义allocator内存池可以直接进行已分配对象的内存池间所有权传递,那么propagate_on_container_move_assignemnt可以为true_type,然后在两个内存池allocator的移动构造函数里做好所有权转移的事情;如果自定义allocator内存池不能转移已分配对象的所有权,那就把propagate_on_container_move_assignemnt设为false,operator==中进行两个内存池的比较,这时候回到上面说的{2, 3}情况,操作依然保证移动的正确性。
源码阅读笔记 - 2 std::vector (2) 关于Allocator Aware Container特性的更多相关文章
- 源码阅读笔记 - 2 std::vector (1)
		
vector的源码真是太长了,今天用了一个下午和一个晚上看和注释了前面的一千行左右 p.s.博客园的代码高亮真是太垃圾, 如果想要阅读带注释的源码,推荐粘贴到VS2015里,然后按ctrl+z取消自动 ...
 - 源码阅读笔记 - 3 std::string 与 Short String Optimization
		
众所周知,大部分情况下,操作一个自动(栈)变量的速度是比操作一个堆上的值的速度快的.然而,栈数组的大小是在编译时确定的(不要说 C99 的VLA,那货的 sizeof 是运行时计算的),但是堆数组的大 ...
 - 源码阅读笔记 - 1 MSVC2015中的std::sort
		
大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...
 - mxnet源码阅读笔记之include
		
写在前面 mxnet代码的规范性比Caffe2要好,看起来核心代码量也小很多,但由于对dmlc其它库的依赖太强,代码的独立性并不好.依赖的第三方库包括: cub dlpack dmlc-core go ...
 - CI框架源码阅读笔记5 基准测试 BenchMark.php
		
上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
 - CI框架源码阅读笔记4 引导文件CodeIgniter.php
		
到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...
 - CI框架源码阅读笔记3 全局函数Common.php
		
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
 - CI框架源码阅读笔记2 一切的入口 index.php
		
上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...
 - Three.js源码阅读笔记-5
		
Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...
 
随机推荐
- ajax的status为201依然触发jquery的error事件的问题
			
昨天在调试一个ajax的时候发现,即使status是201,仍然会触发jquery的error事件.statusText是"parseerror". 通过在stackoverflo ...
 - [驱动开发] struct _LDR_DATA_TABLE_ENTRY
			
@Windows XP Professional Service Pack 3 (x86) (5.1, Build 2600) lkd> dt -b _LDR_DATA_TABLE_ENTRY ...
 - (转) PowerDesigner中Table视图同时显示Code和Name
			
PowerDesigner中Table视图同时显示Code和Name,像下图这样的效果: 实现方法:Tools-Display Preference
 - cocos3.12预编译android报错RuntimeJsImpl.cpp
			
从coco官网下载了cocos2d-x-3.12.zip,在gen-libs生成prebuilt时,mac ,ios 平台都正常,android报错: jni/../../Classes/ide-su ...
 - eclipse控台不见
 - mysql配置命令 CHARACTER_SET_%字符集设置
			
参照: http://blog.csdn.net/mzlqh/article/details/7621307点击打开链接 其实现在的ubuntu12. 直接sudo apt-get install M ...
 - pyside 添加菜单栏,窗口状态栏,工具栏
			
这三个放到一起,个人认为比较有可比性. 另外该写的解释我都记到注释里面了 话不多说,show me the code 菜单栏, # ubuntu16.04触发关联事件不成功,应该是ubantu的全局窗 ...
 - 多系统PE win UBUNTU OSX
			
WIN8 PE来自黑果圈中著名的地平线大神- 内置wim安装工具.EFI修复工具 OSX PE来自 FireWolf OS X PE V7.0 UBUNTU 直接安装盘就能当PE用 需要一个FAT32 ...
 - 在树莓派上部署InfoPi
			
如果仅仅想试用InfoPi,请参照此文在Windows上试用.在Windows上部署比在树莓派上部署简单得多. 先说明一下,我用的系统是Raspbian(2014-06-20发布的). 用户pi,工作 ...
 - 用CorelDRAW等分分割图片的方法
			
在CorelDRAW中,想要将图片等分分割可以通过放置容器来实现,根本不需要裁剪工具和辅助线.例如两等分:首先要建立确定等分的份数,建立长方形或正方形.然后把图片放置容器,调整位置,做无缝拼接就可以了 ...