动态数组
方式一:
int *p = new int[10]; //分配一个一块存储类型为int的连续内存,返回的是这块连续内存的首地址。以默认初始化的方式初始化,内置类型的话,值是随机的。 int *p = new int[10](); //将开辟的内存中的值全都初始化为0 int *p = new int[10]{0,1,2,3,4,5,6,7,8,9}; //使用花括号(这里其实叫初始化器)中的值初始化新开辟的内存中的值。初始化器中值的数目可以小于动态数组的大小,那么不够的地方将默认初始化。但是初始化器中的值不能多于动态数组的大小,会抛出一个bad_array_new_length的异常。
注:动态数组(new出来的数组)其实不是数组,因为我们最终得到不是一个数组对象,而是得到一个数组元素类型的指针。所以不能对动态数组使用begin函数和end函数。
动态分配一个空数组(int *p = new int[0])是合法的,此时new返回一个合法的非空指针,但是不能对这个指针解引用,毕竟它不指向任何有效元素。
释放动态数组:
int *pArray = new int[10](); if(pArray != nullptr) { delete [] pArray; //动态数组中的元素逆序销毁,先销毁最后一个元素,最后销毁的是第一个元素,释放动态数组时,方括号是必须的。 pArray = nullptr; }
方式二:
标准库提供了一个可以管理new分配的数组的unique_ptr版本,为了用一个unique_ptr管理一个动态数组,必须在对象后面跟一个方括号:
unique_ptr<int[]> p(new int[10]);
std::cout << p[0] << std::endl; p.release(); //使用delete []自动释放动态数组
当unique_ptr指向的是一个动态数组的时候,需要用下标运算来访问元素。
shared_ptr不直接支持管理动态数组,如果希望使用shared_ptr管理动态数组,必须提供一个自定义的删除器。shared_ptr不直接支持管理动态数组,所以使用自定义删除器来管理动态数组的时候,不能用下标访问数组元素,而是需要通过get()方法获得内置指针的方式来访问元素。
方式二:
new将内存分配和对象构造组合在了一起,delete将对象析构和内存释放组合在了一起。但这可能会造成浪费,比如,string *p = new string[100];我们可能只用到了其中一部分string,另外,string的赋值进行了两次,一次是new的时候构造的同时默认初始化,另一次是真正使用的时候进行的赋值;还有我们不能为没有默认构造函数的类使用new。
allocator类在头文件memory中,它将内存的分配和对象的构造分离开来,它构造出的内存是原始的、没有被构造的。allocator也是一个模板。
allocator<T> a | 定义一个名为a的allocator的对象,它可以为类型为T的对象分配内存 |
a.allocate(n) | 分配一段原始的、未构造的内存,保存n个数据类型为T的对象 |
a.deallocate(p,n) | 释放从T* 指针p 中地址开始的内存,这块内存保存了n个类型为T的对象,p必须是一个由先前allocate返回的指针,而且n必须是p创建时所要求的大小,在调用deallocate之前,用户必须对每个在这块内存中创建的对象调用destory |
a.constrcut(p,args) | p必须是一个类型为T* 的指针,指向一块原始内存;args被传递给类型为T的构造函数,用来在p指向的内存中构造一个对象 |
a.destory(p) | p为T*类型的指针,此算法对p所指向的对象执行析构函数 |
拷贝和填充未初始化内存的算法
下面的算法也在memory头文件中。是allocator类的伴生算法,可以在未初始化内存中创建对象。
uninitialized_copy(b,e,b2) | 从迭代器b和e指出的范围内拷贝元素到迭代器b2指定的未构造的原始内存中,b2指向的内存必须足够大,能容纳输入序列中元素的拷贝 |
uninitialized_copy_n(b,n,b2) | 从迭代器b指向的元素开始,拷贝n个元素到b2开始的内存中 |
uninitialized_fill(b,e,t) | 在迭代器b和e指定的原始内存范围中创建对象,对象的值均是t的拷贝 |
uninitialized_fill_n(b,n,t) | 从迭代器b指向的内存地址开始创建n个对象。b必须指向足够大的未构造的原始内存,能够容纳给定数量的对象。 |