首页 > 代码库 > 标准库Allocator的使用(一)
标准库Allocator的使用(一)
上一篇我们提到了new运算符以及它的工作步骤,其实无非是把两项工作独立出来:
1.申请原始内存
2.执行构造函数
delete也涉及了两个工作:
1.执行析构函数
2.释放原始内存
其实标准库提供了另外一种更加高级的手段实现内存的分配和构造,就是std::allocator<T>的职责。
allocator提供了四个操作:
a.allocate(num) 为num个元素分配内存
b.construct(p) 将p所指的元素初始化
destroy(p) 销毁p指向的元素
deallocate(p, num) 回收p指向的“可容纳num个元素”的内存空间
使用示例如下:
#include <iostream>#include <string>#include <vector>#include <memory>using namespace std;class Test{ public: Test() { cout << "Test" << endl; } ~Test() { cout << "Test ..." << endl; } Test(const Test &t) { cout << "Copy ....." << endl; } private: //Test(const Test &); //void operator(const Test &);};int main(int argc, const char *argv[]){ allocator<Test> alloc; Test *pt = alloc.allocate(3); //申请三个单位的Test内存 //此时pt指向的是原始内存 { alloc.construct(pt, Test()); //构建一个对象,使用默认值 //调用的是拷贝构造函数 alloc.construct(pt+1, Test()); alloc.construct(pt+2, Test()); } alloc.destroy(pt); alloc.destroy(pt+1); alloc.destroy(pt+2); alloc.deallocate(pt, 3); return 0;}
这里注意,allocator提供的allocate函数与operator new函数区别在于返回值,所以前者更加安全。
还有一点,construct一次只能构造一个对象,而且调用的是拷贝构造函数。
标准库提供了三个算法用于批量构造对象(前提是已经分配内存)
uninitialized_fill(beg, end, val) //以val初始化[beg,end)uninitialized_fill_n(beg, num, val) //以val初始化beg开始的num个元素uninitialized_copy(beg, end, mem) //以[beg, end)的各个元素初始化mem开始的各个元素
以上三个函数操控的对象都是原始内存
示例如下:
#include <iostream>#include <string>#include <vector>#include <memory>#include <stdlib.h>using namespace std;class Test{ public: Test(int val) :val_(val) { cout << "Test" << endl; } ~Test() { cout << "Test ..." << endl; } Test(const Test &t) :val_(t.val_) { cout << "Copy ....." << endl; } int val_;};int main(int argc, const char *argv[]){ Test *pt = (Test *)malloc(3 * sizeof (Test)); Test t(12); uninitialized_fill(pt, pt + 3, t); cout << pt[0].val_ << endl; Test *pt2 = (Test *)malloc(2 * sizeof (Test)); uninitialized_copy(pt, pt + 2, pt2); free(pt); free(pt2);
return 0;}
这里注意标准库的copy、fill函数与uninitialized_系列函数的区别:
copy、fill等操作的是已经初始化对象的内存,因此调用的是赋值运算符
而uninitialized_针对的是原始内存,调用的是拷贝构造函数
OK,我们到此,可以总结出分配原始内存的三种手段:
1.使用malloc
2.使用operator new
3.allocator的allocate函数
这三者从上到下,是一个由低级到高级的过程。
那么执行构造函数,有两种手段:
1.使用placement new运算符
2.使用allocator的construct函数
最后,C语言中的数据都是POD类型,使用原始内存即可,但是C++中的大部分都是POD类型,需要执行相应的初始化函数,所以,在C++中应该尽可能避免使用memcpy之类的直接操控原始内存的函数。
标准库Allocator的使用(一)