new
和delete
只能一次分配释放一个对象,一些场合,我们需要一次为很多对象分配内存,为了支持这种需求,C++标准库提供了两种方法:new
和allocator
。
1 new和数组
一些基本的语法
int *a = new int[get_size()];
int *a = new string[100]();
int *a = new string[10]{"a","b","c",string(3,'x')};
typedef int att[10];
int *a = new att;
delete []a;
智能指针和动态数组可以用unique_ptr
管理动态数组,语法如下:
unique_ptr<int[]> up(new int[10]);
up[i] = 10;
up.release();//自动调用delete[]释放指针
\\此时,指向数组的unique ptr不支持成员访问运算符即 . 和 -> 运算符
\\其他unique ptr操作保持不变
与unique_ptr
不同,shared_ptr
不支持直接管理动态数组,需要自己定义的删除器:
shared_ptr<int> sp(new int[10],[](int *p){delete []p;});//此处使用了lambda表达式
shared_ptr未定义下标运算符,并且不支持指针算术运算符
*(sp.get()+i) = i; //i为我们要访问的下标
2 allocator类
new
和delete
有一些灵活性的局限,将内存分配(释放)和对象构造(析构)组合在了一起,有时这会造成浪费。
标准库allocater
类定义在头文件memory
中,它帮助我们将对象构造和内存分配分离开,它提供一种类型感知的内存分配方法,它分配的内存是原始的,未构造的。
//定义allocator对象,它可以为类型为T的对象分配内存
allocator<T> a;
//分配一段原始的、未构造的内存,保存n个类型为T的对象
auto p = a.allocate(n);
//在p指向的内存中构造一个对象
a.construct(p,args);
//对p指向的对象执行析构函数
a.destroy(p);
//释放从T*指针 p中地址开始的内存,这块内存保存了n个对象;
//p必须先用allocate分配返回的指针,并且需要使用destroy析构对象后才能调用deallocate
a.deallocate(p,n);
以下为使用示例:
allocator<string> alloc;
auto const p = alloc.allocate(n);//分配n个未初始化的string
auto q = p;
alloc.construct(q++);//*p为空字符串
alloc.construct(q++,10,'c');//*p为cccccccccc
alloc.construct(q++,"h1");//*p为hi
while(q!=p)
alloc.destroy(--q);//被销毁后,可以重新构造,注意是前置--
alloc.deallocate(p,n);
标准库还为allocator
类定义了两个伴随算法,用来进行拷贝和填充操作:
//从迭代器b和e指出的范围中拷贝元素到迭代器b2开始的未构造内存中
uninitialized_copy(b,e,b2);
//将从迭代其b开始n个元素拷贝到迭代器b2开始的内存中
uninitialized_copy(b,n,b2);
//在迭代器b和e指出的范围中创建t的拷贝对象(多个)
uninitialized_fill(b,e,t);
//从b开始的内存中创建n个t对象
uninitialized_fill(b,n,t);