浅谈C++ allocator内存管理(对比new的局限性)

我自己搭建了博客,以后可能不太在CSDN上发博文了,https://www.qingdujun.com/


STL中,对内存管理的alloc的设计,迫使我去学习了allocator类。这里对allocator内存管理做了点笔记留给自己后续查阅。allocator类声明、定义于头文件<memory>中的std命名空间内。所以,应该有以下内容位于文件头部…

#include <memory>
using namespace std;


1. 我们所知道的malloc和new

再此之前,我只知道两种开辟内存的方式。

其一,可以使用C语言的函数malloc、realloc、calloc开辟内存,举个例子:

int* ptr = (int *)malloc(10 * sizeof(int));	/* 进行强制类型转换 */

其二,可以使用C++方式开辟内存,比如:

int* ptr = new int[10];

对于,C风格的内存管理这里不做讨论。但是,对于C++的new风格,这里总结一下它的局限性。对于我个人来说,我一般写成这样new int[10](),也就是在最后加一对小括号,因为C++保证这样可以将int[10]中内存全部初始化为0。

2. C++中new的局限性

对于以上这一段话,有一个话题需要弄清楚的,就是——内存构造。

对C++的new而言,它首先会(1)分配内存,然后自动的完成(2)对象构造。这里可以用侯捷先生翻译的《深度探索C++对象模型》一书中的伪代码来表示new的过程:

Point* heap = __new(sizeof(Point));//开辟内存
if (head != 0) {
	head->Point::Point();//对象构造(内存构造)
}

注意,__new不表示new(它只是完成内存申请),以上整个伪代码过程为new所完成的功能。
正是因为new的这一连串的操作,造成了性能的下降。比如,

auto p = new string[100];
for (int i = 0; i < 5; ++i){
	p[i] = "balaba...";
}

实际上,我只需要5个string,而new把100个对象全部构造好了(每个string已经被初始化为空字符串,也就是"")。

然后,接着又将p[0-4]赋值为balaba…

也就是前面将p[0-4]赋值为空字符串的操作,变得毫无意义。

3. 使用allocator将内存分配、对象构造分离开

既然,new有它自身的局限性。对于性能要求极高的STL肯定是不会使用new的。好在有一个allocator类——它也是一个模板类,同时就是用来处理内存问题的。

allocator类将new的内存分配、对象构造,视作两个独立的过程,并由独立的函数负责。举个例子:

allocator<char> str;
char* base = str.allocate(10), *p = base; //内存分配
str.construct(p++, 'a');  //对象构造并初始化
str.construct(p++, 'b');
cout << base[0] << base[1];

因为allocator是模板类,所以需要指定类型。接着,调用allocate(10)函数来分配内存(申请了10个char内存)。然后,使用construct函数构造base[0]这块内存,并赋以初值a

这就将new内存分配、内存构造给分离开了。一切,都像我们看到的那样。

同样,将delete的过程也拆分了开来。这是必须的,我们不能用delete去释放allocate分配的内存。

str.destroy(--p); //销毁对象
str.destroy(--p);
str.deallocate(base, 10); //释放内存

小结:如果要使用allocate返回的内存,那么就必须先construct构造它。否则,你后续的行为都是未定义的(造成的后果也是严重的)。

但是,有几个例外。它们是uninitialized_copy、uninitialized_copy_n、uninitialized_fill和uninitialized_fill_n。从名字就知道uninitialized(未初始化的),它们的参数必须指向的是未构造的内存,比如uninitialized_copy会在给定位置构造元素。

有兴趣可以阅读《动态内存管理allocator类C++ STL标准模板库vector实现》看看它们的用法。



©为径
2018-12-23 北京 海淀


Reference:
[1] C++ Primer(第5版)
[2] 深度探索C++对象模型

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页