动态数组的分配和释放
- new和数组
int* arr = new int[20]; // arr 指向第一个int
方括号中的大小必须是整数,但不必是常量。
typedef int arrT[42];
int* p = new arrT; // 分配一个42个int的数组,p指向第一个int
虽然我们通常称 new T[ ] 分配的内存为 “动态数组”, 这种叫法在某种程度上来说有些误导。使用new分配一个数组时,我们只是获得了一个数组元素类型的指针,并未获得一个数组类型的对象。因此,动态数组并不是数组类型。因此,不能对动态数组使用begin()和end(),这些函数使用数组的维度,也不能处理数组中的元素,比如for语句。
- 初始化动态分配对象的数组
int* pia = new int[10]; // 10个未初始化的int
int* pia1 = new int[10](); // 10个值初始化的int
string* psa = new string[10]; // 10个空string
string* psa = new string[10](); // 10个空string
新标准中,我们可以提供一个元素初始化器的花括号列表:
int* pia2 = new int[10]{0, 1, 2, 3, 4, 5, 6};
如果花括号中的元素个数少于分配对象个数,剩余的元素进行值初始化,如果元素个数多余对象个数,则new表达式失败,不会分配内存。new会抛出一个bad_array_new_length的异常,类似bad_alloc,该异常类型定义在头文件 <new>中。
- 动态分配一个空数组是合法的
char* pc = new char(0);
此时new返回一个与其他new表达式返回类型都不同的指针类型,该指针不能解引用,就像一个数组的尾后迭代器一样。
- 释放动态数组
数组中的元素逆序销毁,即,最后一个元素首先被销毁,然后是倒数第二个,依次类推。
智能指针和动态数组
unique_ptr<int[]> up(new int[10]());
up.release(); // 自动调用delete []销毁其指针
当一个unique_ptr指向一个数组时,我们不能使用点和箭头成员运算符,毕竟,unique_ptr指向的是一个数组而不是单个对象。不过,我们可以使用下表运算符来访问数组中的元素:
for (size_t i = 0; i < 10; ++i)
up[i] = i;
shared_ptr不支持动态数组,如果希望使用shared_ptr管理一个动态数组,我们需要提供自己的删除器:
shared_ptr<int> sp(new int[10], [](int* p){ delete [] p; });
sp.reset();
我们在这个例子中使用lambda做为shared_ptr的删除器,如果我们不提供删除器,这样的行为是未定义的,因为默认情况下shared_ptr使用delete来释放内存,使用delete来释放一个动态数组的定位是未定义的。
for (size_t i = 0; i != 10; ++i)
*(sp.get() + i) = i;
shared_ptr没有定义下标运算符,而且智能指针不支持指针算术运算。因此,为了访问数组中的元素,我们必须用get成员函数获取一个内置指针,然后使用该内置指针来访问数租元素。