动态数组的分配和释放

  • new和数组
C++语言和标准库提供了一次分配一个对象数组的方法,定义了另一种new表达式语法。我们需要在类型名后跟一对方括号,在其中指明要分配的对象的数目。
int* arr = new int[20]; // arr 指向第一个int

方括号中的大小必须是整数,但不必是常量。

可以使用typedef来表示数组类型的别名:
typedef int arrT[42];
int* p = new arrT; // 分配一个42个int的数组,p指向第一个int

虽然我们通常称 new T[ ] 分配的内存为 “动态数组”, 这种叫法在某种程度上来说有些误导。使用new分配一个数组时,我们只是获得了一个数组元素类型的指针,并未获得一个数组类型的对象。因此,动态数组并不是数组类型。因此,不能对动态数组使用begin()和end(),这些函数使用数组的维度,也不能处理数组中的元素,比如for语句。

  • 初始化动态分配对象的数组
可以对new分配的动态数组进行值初始化,方法时在大小后面跟一对空括号:
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>中。

new一个非数组对象时,我们可以在初始化括号中给出一个初始化器,依靠这个初始化器,我们可以使用auto来分配数组,但是对于数组,这种做法是不允许的。
  • 动态分配一个空数组是合法的
我们在使用new分配一个动态数组时,可以指定分配数组的大小为0,这样做是合法的:
char* pc = new char(0);

此时new返回一个与其他new表达式返回类型都不同的指针类型,该指针不能解引用,就像一个数组的尾后迭代器一样。

  • 释放动态数组
释放动态数组,我们需要在delete和数组名之间加一个空的方括号[ ] , 表示我们释放的是一个动态数组。
数组中的元素逆序销毁,即,最后一个元素首先被销毁,然后是倒数第二个,依次类推。
当我们释放一个动态数组时,空方括号是必须的,它指示编译器此指针指向一个对象数组的第一个元素。 delete一个动态数组时未添加空方括号或delete一个普通指针时添加了空方括号,其行为都是未定义的。
前面我们讲到,可以使用typedef来给动态数组起一个别名,这样在new一个动态数组时就不必添加方括号[],即使这样,我们在释放一个动态数组时,仍然需要添加方括号[],因为它本质上还是一个动态数组。

智能指针和动态数组

unique_ptr智能指针有个可以管理new分配的动态数组的版本,为了使用一个unique_ptr来管理动态数组,需要在对象类型后加一个空方括号[]:
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来释放一个动态数组的定位是未定义的。

shared_ptr不支持动态数组这一特性会影响我们访问数组中的元素:
for (size_t i = 0; i != 10; ++i)
*(sp.get() + i) = i;

shared_ptr没有定义下标运算符,而且智能指针不支持指针算术运算。因此,为了访问数组中的元素,我们必须用get成员函数获取一个内置指针,然后使用该内置指针来访问数租元素。

C++ Primer : 第十二章 : 动态内存之动态数组的更多相关文章

  1. C++ Primer : 第十二章 : 动态内存之shared_ptr与new的结合使用、智能指针异常

    shared_ptr和new结合使用 一个shared_ptr默认初始化为一个空指针.我们也可以使用new返回的指针来初始化一个shared_ptr: shared_ptr<double> ...

  2. C++ Primer : 第十二章 : 动态内存之动态内存管理(new和delete)

    C++语言定义了两个运算符来分配和释放动态内存:运算符new分配内存,运算符delete释放new分配的内存. 运算符new和delete 使用new动态分配和初始化对象 在自由空间分配的内存是无名的 ...

  3. C++ Primer : 第十二章 : 动态内存之shared_ptr类实例:StrBlob类

    StrBlob是一个管理string的类,借助标准库容器vector,以及动态内存管理类shared_ptr,我们将vector保存在动态内存里,这样就能在多个对象之间共享内存. 定义StrBlob类 ...

  4. C++ Primer : 第十二章 : 动态内存之shared_ptr类

    在C++中,动态内存是的管理是通过一对运算符来完成的:new  ,在动态内存中为对象分配空间并返回一个指向该对象的指针,delete接受一个动态对象的指针,销毁该对象,并释放该对象关联的内存. 动态内 ...

  5. Linux内核设计与实现 总结笔记(第十二章)内存管理

    内核里的内存分配不像其他地方分配内存那么容易,内核的内存分配不能简单便捷的使用,分配机制也不能太复杂. 一.页 内核把页作为内存管理的基本单位,尽管处理器最小寻址坑是是字或者字节.但是内存管理单元MM ...

  6. C++Primer 第十二章

    //1.标准库提供了两种智能指针类型来管理动态对象,均定义在头文件memory中,声明在std命名空间. // shared_ptr:允许多个指针指向同一个对象. // unique_ptr:独占所指 ...

  7. C++ Primer : 第十二章 : 动态内存之allocator类

    标准库allocator类定义在头文件 <memory>中.它帮助我们将内存分配和构造分离开来,它分配的内存是原始的.未构造的. 类似vector,allocator也是一个模板类,我们在 ...

  8. C++ Primer : 第十二章 : 动态内存之unique_ptr和weak_ptr

    unique_ptr 一个unique_ptr拥有它所管理的对象,与shared_ptr不同,unique_ptr指向的对象只能有一个用户.当unique_ptr被销毁后,它所指向的对象也被销毁. 定 ...

  9. C++ Primer : 第十二章 : 文本查询程序

    C++ Primer书上这个例子讲的很不错,写写帮助自己理解标准库和智能指针. .h 文件内容 #include <fstream> #include <iostream> # ...

随机推荐

  1. PowerMock与EasyMock的应用(转)

    Leader请求在做Junit测试的时辰,Mock掉各个办法之间的依附.这两天进修了下PowerMock的应用. PowerMock是EasyMock的一个扩大,参加了static,final,pri ...

  2. Fair Photography

    题目大意: 给出直线上N个点的位置和颜色(0或1),求最大的区间,使得区间内0的个数大于等于1的个数且0的个数减去1的个数为偶数. 解题过程: 1.先贴个lsdsjy大牛的线段树的做法:http:// ...

  3. IBatis.Net 表连接查询(五)

    IBatis.Net之多表查询: 一.定制实际对应类的方式 首先配置多表的测试数据库,IBatis.Net之Oracle表连接查询配置: 首先新建两张表如下: 为两张表建立外键: ALTER TABL ...

  4. Fragment 切换问题

    public void switchContent(Fragment fragment) { if(mContent != fragment) { mContent = fragment; mFrag ...

  5. objective-c strong导致内存泄漏简单案例

    例如: @interface Test:NSObject{ id __strong obj_; } -(void) setObject:(id __strong)obj; @end @implemen ...

  6. JAVA 打印九九乘法表

    /** *  * @author liangxiaoyu * @version 1.0 *2015-09-18 */public class JJ { public static void main( ...

  7. SQL优化-索引

    (一)深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonc ...

  8. C++11 move_iterator

    template<typename Iterator> class move_iterator { Iterator current; public: typedef Iterator i ...

  9. linux下解决端口被占用的问题

    以端口9877为例,先查看是否有进程占用该端口 netstat -tln | grep 9877 然后查看占用该端口的进程的进程id lsof -i :9877 最后kill 命令结束该进程: kil ...

  10. __set()与__get() 魔术方法

    在面向对象编程的过程中,对于类当中的各个成员变量,都有不同的访问属性,比如公有的(public)属性,在类内部和类外部都可直接调用:而私有的(private)和受保护的(protected),在类外不 ...