管理动态内存的方法

我们所编写的程序中所使用的对象都有着严格定义的生存期。全局对象在程序启动时分配,在程序结束时销毁;对于局部自动对象,当我们进入其定义所在的程序是被创建,在离开时被销毁。局部static对象在第一次使用前分配,在程序结束时销毁。

在编写程序时,除了要管理自动和static对象外,还需要管理动态内存,而动态内存的生存期与它们在哪里创建无关,只有当显式地被释放时,才会被销毁,而往往在写程序时,我们很容易忘记显式的释放动态内存,这样很容易造成内存泄露,造成程序崩溃,而这些错误往往编译器是发现不了的,不会提醒程序员,所以对动态内存的管理非常重要。

这里,介绍两种常见的动态内存管理方法。

1.使用new和delete对来管理;

2.使用智能指针来管理,其中使用shared_ptr 和make_shared。

第一种:使用new和delete对来管理

   这是常见的一种管理方法,也是我们最常用的一种方法,通常new和delete是成对的出现,当用new为一个对象申请了内存后,必须在使用完后,使用delete来销毁内存。

例:int *p = new int;//p指向一个动态内存的,未初始化的无名对象

此时,new表达式在自由空间构造一个int对象,并返回指向该对象的指针。在使用完p之后,后面不在使用的时候一定要技能用delete来销毁内存,

delete p;

这里使用delete后,程序会销毁申请的内存,但是此时指针p还是指向那个内存,只是内存此时无用,这里为了避免后面又使用到该指针,我们还需要在后面将p赋值为空指针。

p = nullptr;

第二种:使用智能指针来管理动态内存

这里主要是使用shared_ptr和make_shared来管理。使用智能指针可以避免程序员忘记销毁内存而造成的内存泄露,从而导致的系统崩溃。因为它当没有指针指向该内存的时候会自动释放内存。

例:shared_ptr<int> *p = make_shared<int>();这里也是p指向一个动态内存,其值初始化为0

这里我们建议使用智能指针来管理动态内存。具体优势,我们通过下面的例子来解释:

int *q = new int(42), *r = new int(100);
r = q;
auto *q2 = make_shared<int>(42), r2 = make_shared<int>(100);
r2 = q2;

 下面我们解释这段程序。

对于普通指针部分,首先分配了两个int型对象,指针分别保存在p和r中。接下来,将指针q的值赋给了指针r,这样带来了两个非常严重的内存管理问题。

1.首先是一个直接的内存泄露问题,r和q一样都指向42的内存地址,而r中原来保存的地址--100的内存再无指针管理,变成“孤儿内存”,从而造成内存泄露。

2.其次是一个“空悬指针”问题。由于r和q指向同一个动态对象,如果程序编写不当,很容易产生释放了其中一个指针,而继续使用另一个指针的问题。继续使用另一个指针指向的是一块已经释放的内存,是一个空悬指针,继续读写它指向的内存可能导致程序崩溃甚至系统崩溃的严重问题。

而shared_ptr则可以很好的解决这个问题。首先,分配了两个共享的对象,分别由指针p2和r2指向,因此它们的引用次数都为1.接下来,将q2赋予r2.赋值操作会将q2指向的地址赋予r2,并将r2原来指向的对象的引用次数减1,将q2指向的对象的引用次数加1.这样,前者的引用次数变为0,其占用的内存空间会被释放,不会造成内存泄露。而后者的引用计数变为2,也不会因为r2和q2之一的销毁而释放它的内存空间,因此也不会造成空悬指针的问题。

从上面的例子可以看出,使用智能指针比使用new和delete更方便,更实用,可以避免我们编写代码时的很多内存管理问题。

原文地址:https://www.cnblogs.com/pengjun-shanghai/p/5010183.html