c++ allocator
C++中,动态内存可以用new来实现,即在堆上申请空间,并需要显示释放这块动态内存。当然,也可以用智能指针来实现。
new有一个缺陷,就是把内存分配和对象构造结合在了一起。对于单个对象,这是很方便的,然而对于大块的内存时,可能需要先申请空间,然后陆续执行构造,此时需要将内存分配和对象构造分离开来。allocator类就提供了这样的功能。
先来看一段使用new的例子:
string* q = new string[10];//申请了10个stirng的空间,并进行默认初始化 string s; string *pp = q; while (cin >> s&&pp != q + 10)//再次为这些string赋值 *q++ = s; delete[] q;
可见,对象实际上执行了一次初始化和一次赋值,而实际上初始化的过程是不必要的。
接下来,先用allocator重写一遍,然后再解释一下allocator的操作:
allocator<string> alloc;//分配string类型的allocator auto p = alloc.allocate(10);//分配10个string空间 auto q = p; string s; while (cin >> s&&q != p + 10) alloc.construct(q++, s);//用输入的值构造元素 while (q != p) alloc.destroy(--q);//逐一销毁元素 alloc.deallocate(p, 10);//释放内存空间
首先,allocator是一个模板,需要指定分配内存的类型。allocator的主要操作如下:
alloc.allocate(n);//分配一段原始的内存,保存n个元素,返回首地址 alloc.construct(p, args);//在p的位置,用args调用构造函数,构造一个对象 alloc.destroy(p);//对p指向的对象调用析构函数 alloc.deallocate(p, n);//释放空间,注意n必须与分配的大小参数相等
有几个地方需要注意:
1.分配的内存是没有构造的,使用这些原始内存时错误的,也不能直接对这些内存进行赋值!
2.构造后,如果想释放这块内存,需要先进行销毁,并且必须对构造过的元素进行销毁。
3.分配和释放内存的大小必须相等。
因为allocator可以方便地分配一段内存,于是标准库提供了两组函数,来对整段的区域进行创建对象的操作:
uninitialized_copy(b, e, b2);//把迭代器b,e之间的元素拷贝到指针b2开始的内存中,b2内存足够大 uninitialized_copy_n(b, n, b2);//从b起的n个元素拷贝到指针b2开始的内存中 uninitialized_fill(b, e, t);//同上,对象的值均为t的拷贝 uninitialized_fill_n(b, n, t);//同上,对象的值均为t的拷贝
不过这些函数看到有人不推荐使用,VS中也会进行报错或者警告,因为是提供给内部使用的函数,前者推荐用copy和copy_n来代替,后者推荐用fill和fill_n来代替。