C++primer(第五版)第十二章(动态内存)

C++中内存包含静态内存,栈内存,自由空间(堆).

静态内存用于保存局部的static(静态)对象,以及定义于任何函数以外的变量(全局变量).

栈内存用来保存定义在函数内的非static对象,由编译器自动创建和销毁.

程序可以用堆来存储动态分配的对象,同时也需要由我们来显式地销毁.

12.1动态内存与智能指针

C++中动态内存的管理是由new和delete来完成的,由new来为对象分配空间并返回指向该对象的指针.由delete来对指针指向的对象进行销毁.

int *i=new int(10);   //创建
cout<<*i<endl;        //使用
delete i;             //销毁
cout<<*i<endl;        //抛出异常

新的标准库提供了两种智能指针(shared_ptr,unique_ptr),智能指针可以自动释放内存!

另外标准库还定义了名为weak_ptr的伴随类,它指向shared_ptr所管理的对象.

以上三种类型都定义在头文件memory头文件中.

12.1.1 shared_ptr类

智能指针也是模板,需提供指针可以指向的类型.

shared_ptr<string> p1;        //p1是可以指向string的shared_ptr
shared_ptr<vector<int>> p2;   //p2是可以指向元素类型为int的vector的shared_ptr

 默认初始化的智能指针中保存空指针.

 最安全的分配和使用动态内存的方法是调用来自标准库的函数make_shared,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr.我们一般用auto来接收,因为写起来比较简单.

shared_ptr<int> p1=make_shared<int>(10);    //一个指向10的shared_ptr
auto p2=make_shared<vector<int>>();        //一个指向元素类型为int的空vector的shared_ptr

当shared_ptr被拷贝或是赋值时,会有一个关联的计数器(可以这么理解)来记录有多少个其他shared_ptr指向相同的对象.可以通过p.use_count()来获取查看有多少个,主要用于调试.

当我们拷贝shared_ptr时,计数器会加一.当我们给shared_ptr赋予新值或是销毁时(离开作用域),计数器会减一,当计数器为0是,shared_ptr会自动释放自己所管理的对象.

shared_ptr除了自动销毁所管理的对象,还会自动释放相关联的内存.

使用动态内存通常出于以下三种原因:

程序不知道自己需要多少对象.

程序不知道所需对象的准确类型.

程序需要在多个对象间共享数据.

12.1.2直接管理内存

可以使用new来分配const对象,并且必须进行初始化.分配的是const对象时,new返回的是指向const的指针.

如果我们的自由空间耗尽,那么new会失败,并且抛出异常.我们可以改变new的方式来阻止抛出异常:

int *p=new (nothrow) int;    //如果分配失败,那么p为空指针(nullptr)而不是抛出异常

通常情况下,编译器无法分辨指针的指向,因此在释放内存前最好是先判断一下要释放的指针是否为空指针. 

内置指针(非智能指针)管理的动态内存在被显式释放之前都会一直存在,因此我们需要记得去释放,否则是及其消耗内存的.

使用内置指针通常会犯以下三个错误(因此书中推荐使用智能指针):

忘记delete内存.

使用已被释放的对象.

同一块内存释放两次.

delete之后,指针变成空悬指针,如果需要保留指针,那么最好是在delete之后,将其赋值为nullptr(空指针).

12.1.3 shared_ptr和new结合使用

使用new来初始化智能指针必须使用直接初始化形式:

shared_ptr<int> p1(new int(10));    //正确,使用直接初始化形式
shared_ptr<int> p2=new int(10);    //错误,new返回的是int*而不是shared_ptr

可以使用new,但是还是推荐使用shared_ptr.

并且非常不推荐混用普通指针和智能指针.

12.1.4智能指针和异常

智能指针的异常通常出现在get函数身上,p.get()会返回p保存的指针,如果智能指针p释放的其对象,那么get函数返回的指针指向的对象也会消失,因此只有确定代码不会delete指针的情况下才能使用get,并且不要用get初始化另一个智能指针或是给智能指针赋值.

为了减少异常,我们需坚持以下几条基本规范:

 12.1.5 unique_ptr

使用上unique_ptr和shared_ptr差不多.

不同的是unique_ptr一个时刻只能有一个unique_ptr指向一个对象,并且初始化时必须采用直接初始化形式.unique_ptr不支持拷贝或赋值操作.

 12.1.6 weak_ptr

weak_ptr是一种不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的对象.

 创建weak_ptr时需要一个shared_ptr来初始化它.

来通过weak_ptr访问对象时需要先用w.lock()来检查一下指向的对象是否存在

12.2动态数组

虽然书中有介绍动态数组的这个章节,但是同时也说了更推荐使用标准库容器.因此不再多介绍,只提炼出几点需要注意的点.

使用动态数组需要牢记动态数组并不是数组类型.

delete释放动态数组需要在delete后加上方括号[].

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值