C++ 智能指针

在C++中,动态内存的管理通过new 和 delete来进行。
但却经常存在以下三个常见问题:

  1. 忘记通过delete 释放内存,这在编程中经常发生,尤其在某个函数内申请的一块内存作为临时使用,但在函数结束后却没释放。这就会导致“内存泄露”问题。
  2. 使用已经释放过的内存,当有多个指针指向同一块内存时,某个指针释放后,却仍旧使用其他指针,就会导致这种错误。通过释放内存后把指针置为空,可以解决这种情况。
  3. 同一个块内存被释放多次,同样是多个指针指向同一块内存时,不当操作会导致这个情况。

所以在新的标准库里面,提供了两种智能指针shared_ptr类 和 unique_ptr类,均在 <memroy> 头文件

shared_ptr 类

允许多个指针指向同一个对象或内存,创建时需要指明类型
shared_ptr<int> p ;//一个空的shared_ptr,可以指向int

shared_ptr的操作 含义
p 可以当做判断是否为空,若p指向一个对象或内存,返回true。否则返回false
*p 获得p指向的对象的值
p.get() 返回p中保存的指针(不要过多使用,当智能指针释放后,返回的这个指针指向的内存也会被释放)
p.swap(q) 交换p,q的指针
shared_ptr<T> p(q) p 是 q(shared_ptr类型)的拷贝,二者会指向同一块内存
p.unique() 若指向该内存的shared_ptr指针只有一个则返回true,否则返回false,即判断p.use_count()的值是否为1
p.use_count() 返回与p共享对象的智能指针数量(注意只有智能指针),如是p.get()返回一个普通指针被拷贝,use_count不会增加,注意该函数会很慢
p.reset() 如果p是唯一的指针,那么该函数会释放此对象,并置空。
p.reset(q) q是一个普通指针,那么会释放原对象,把p指向q
p.reset(q,d) d是一个删除器,可以是一个lambda表达式同上,释放对象时是调用d而不是delete

特点:
每个shared_ptr都关联一个计数器,通常称为引用计数。每当拷贝一个shared_ptr计数器都会增加。每当销毁一个共享的shared_ptr,计数器就会减小。当计数器减为0,他就会自动释放自己所指向的对象或内存。
释放内存的工作是交给析构函数来完成的。

shared_ptr和new的结合

shared_ptr可以通过new来分配内存,但不能将一个内置指针转化为一个只能指针,必须使用直接初始化的形式。如下

shared_ptr<int> p(new int(3);//这里p指向一个值为3的int
shared_ptr<int> p = new int(3);//注意,这里会报错。必须直接初始化

报错的原因是,new 返回的是一个int*。

make_shared 函数

最安全的分配和使用动态内存的方法,就是这个make_shared 标准库函数
该函数在动态内存中分配一个对象并初始化它,返回该对象的shared_ptr。该函数也在
<memory>中。使用make_shared也要求指定创建的对象类型,与模板类相似.

shared_ptr<int> p1 = make_shared<int>(3);//p1指向一个值为3的int
shared_ptr<string> p2 = make_shared<string>(3,'9');//p2指向一个"999"的string
shared_ptr<int> p3 = make_shared<int>();//p3指向一个值为0的初始化的int.
shared_ptr的拷贝和赋值
shared_ptr<int> p = make_shared<int>(3);
shared_ptr<int> q(p);//q也指向了这块内存,计数器会加一
shared_ptr<int> r = p;//r也指向了这块内存,计数器再加一

切记不要混用普通指针和智能指针。
如果使用普通指针通过.get()和智能指针指向同一个块地址,智能指针的计数器是不会增加的。当智能指针释放内存后。普通指针就会变成悬空指针(指向的内存被释放)如果再被使用,就会不安全且不可靠。

unique_ptr 类

unique_ptr会“独享”它所指向的对象,任何时刻都时只能有一个unique_ptr指向对象。unique_ptr被销毁时,它所指向的对象也会被销毁。
与shared_ptr不同,没有对应的类似make_shared的标准函数返回一个unqiue_ptr,所以必须使用new 返回的指针来进行初始化。即unique_ptr必须使用直接初始化形式。

unique_ptr<int> p1;//可以指向一个int的unique_ptr
unique_ptr<int> p2(new int(3));//指向一个值为3的int
unique_ptr<int> p3(p2);//报错,无法拷贝
unique_ptr<int> p3 = p2;//报错,unique_ptr不支持赋值,包括其他类型的地址也无法直接赋值
操作 含义
unique_ptr<T> u 空的unique_ptr,可以指向T类型的对象
u.release() 放弃对指针的控制,返回指针,并把u置空
u.reset() 释放u所指向的对象
u.reset(q) 如果q时一个指针,那么u指向这个对象

通过releae或reset可以实现指针的转移。

unique_ptr<int> u1(new int(3));
unique_ptr<int> u2(u1.release());//u2指向这个值为3的int。u1会置空.
unique_ptr<int> u3(new int(2));
u3.reset(u2);//u3会释放原内存,现在指向值为3的int

参看书籍:

  • 《C++ primer》 第五版
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章