动态数组:
动态数组不是数组,只是一串动态分配的连续内存空间,指向动态数组的指针是指向该连续空间的首元素地址。
可以申请一个大小为0的动态数组,但不能申请一个大小为0的数组。但C++中通常使用动态数组来完成数组行为。
释放动态数组:
释放动态数组使用delete[] p; delete[] p 和delete p 的区别在于delete[] p会调用多次析构函数,而delete p只调用一次,但对于内置数据类型它们的效果一样,因为内置数据类型没有析构函数。
可以使用一个unique_ptr指向一个动态数组:
unique_ptr<int> up = new int[10];// 元素默认初始化,up中保存的是首元素地址
unique_ptr<int> up = new int[10](); // 元素值初始化
释放unique_ptr:
up.release(); // 销毁指针保留内存
使用unique_ptr管理动态数组时不能使用点运算符和箭头运算符,但可以使用下标, 如:up[5];
shared_ptr不直接支持动态数组,需要自定义删除器:
shared_ptr<int> sp (new int[10], [](int* p){delete[] p;}); // 删除器操作的对象是shared_ptr保存的指针
sp.reset(); // 若计数为0,使用提供的lambda表达式删除sp所指向的对象
shared_ptr未定义下标运算,并且不支持指针与整数的运算,所以使用shared_ptr管理动态数组,只能用sp.get()获取其内置指针后访问: *(sp.get()+2) = i;
allocator类:
将内存分配与创建对象分离的类,用于管理连续的多个动态内存对象;它分配大块内存并在需要使用时才创建指针对象;
头文件:allocator
allocator类操作:
#include<allocator>
allocator<T> a;
a.allocate(n); // 分配n个动态内存, 并返回一个指向首元素的指针
a.deallocate(p, n); // 回收p指向的n个内存(创建时必须使用的是p、n),回收时内存中的对象必须已执行destroy
a.construct(p, args); // 在p指向的内存中以args为构造参数构造一个对象
a.destroy(p); // 对p所指对象进行析构
一个完整使用allocator类的案例:
以下案例演示了申请一个对象到回收一个对象的过程
#include<allocator>
std::allocator<string> a;
auto const* p = a.allocate(10); // p是指向allocte申请的10个动态内存的首元素的指针。
auto q = p;
a.construct(q++); // 创建一个对象,该对象默认初始化
a.construct(q++, 10, 'c'); // 在申请内存中的第二个位置创建对象,对象的值是"cccccccccc"
a.construct(q++, "abc");
// statements
while( q != p){
a.destroy(--q);
} // 销毁在内存上创建的对象
a.deallocate(p, 10); // 回收内存
allocator类的uninitialized系列:
allocator类的uninitialized系列(拷贝或填充原始空间)算法可以在指针指向的原始空间中,创建对象:
- uninitialized_copy(b, e, b2); // 将迭代器序列中[b, e)的元素拷贝到b2所指的原始空间,返回指向最后一个构造元素之后的指针
- uninitalized_copy_n(b, n, b2); // 将从b开始的n个元素序列拷贝到b2所指的原始空间,返回指向最后一个构造元素之后的指针
- uninitalized_fill(b, e, t); // 用t值填充构造[b, e)的原始空间,返回指向最后一个构造元素之后的指针
- uninitialized_fill_n(b, n, t); // 用n个t值填充构造从b开始的原始空间,返回指向最后一个构造元素之后的指针