动态数组的分配和释放

  • 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. Android事件处理--读书笔记

    2013-12-28 17:57:17 1. Android提供了两种方式的事件处理:基于回调和基于监听的事件处理: 1.1 对基于监听的事件处理而言,主要做法是为Android界面组件绑定特定的事件 ...

  2. cmd打开控制面板及其他命令

    如果你在权限较小的域用户的机器上,要做一些管理操作,就不可避免的要使用cmd打开一些以前只能在图形界面里打开的程序.下面是我收集的一些常用操作. 以某个身份启动程序:runas /user:it\n1 ...

  3. HDU 5451 广义斐波那契数列

    这道题目可以先转化: 令f(1) = 5+2√6 f(2) = f(1)*(5+2√6) ... f(n) = f(n-1)*(5+2√6) f(n) = f(n-1)*(10-(5-2√6)) = ...

  4. Program D--贪心-区间覆盖

    Given several segments of line (int the X axis) with coordinates [Li,Ri]. You are to choose the mini ...

  5. [转] lib和dll 区别,生成及使用方法

    lib 和 dll 的区别.生成以及使用详解 [目录] lib dll介绍 生成动态库 调用动态库 生成静态库 调用静态库 首先介绍一下静态库(静态链接库).动态库(动态链接库)的概念,首先两者都是代 ...

  6. Lib New

    gacutil /if E:\ThirdParty\RockyLib\Rocky\bin\Release\Rocky.dll gacutil /u Rocky partial class GmailF ...

  7. Java基础毕向东day04

    1. 数组 2.选择排序.冒泡排序.折半查找.

  8. java应用程序和虚拟机实例之间的关系

    每一个java程序都会产生一个java虚拟机的实例.并不是说一个物理机上,运行多个java应用程序就只有一个java虚拟机实例,多少个java应用程序就有多少个java虚拟机实例.

  9. struts调用的几种方法

    在Struts2中方法调用概括起来主要有三种形式 第一种方式:指定method属性 <action name="student" class="com.itmyho ...

  10. 巧用nginx屏蔽对用户不可见的文件

    事情的起因是这样的--前端的项目中有一些.less之类的源文件,而为了方便迭代更新发布,直接就把整个工程放到了www目录下. 这样虽然方便了,但是会带来一些安全隐患——用户可以访问/盗取这些源文件. ...