C++动态内存管理之智能指针

前言

        动态内存管理引起的所谓内存泄漏的问题是编程领域的一大顽疾,它的成因非常直截了当---只拿不还”,但它产生的缘由有时却非常隐晦需要非常仔细布局你的每一行代码才能抵抗它们对你的系统的侵蚀。而智能指针就能解决上面的问题,它的主要的功能就是自动帮我们管理内存。

一、智能指针

1、智能指针主要解决以下问题

  • 内存泄漏:内存手动释放,使用智能指针可以自动释放
  • 共享所有权指针的传播和释放,比如多线程使用同一个对象时析构问题

2、 智能指针的类型(其中后三个是C++11支持,并且第一个auto_ptr已经被C++11弃用
  • auto_ptr 
  • shared_ptr  共享对象的所有权,但性能略差。
  • unique_ptr   独占对象的所有权,由于没有引用计数,因此性能较好。
  • weak_ptr     配合shared_ptr,解决循环引用的问题

3、智能指针的使用

3.1 shared_ptr

3.1.1 内存模型:

shared_ptr 内部包含两个指针,一个指向对象,另一个指向控制块 (control block) ,控制块中包含一个引用计数(reference count), 一个弱计数 (weak count)和其它一些数据,内存模型如下图1。

  • std::shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存,每拷贝一次引用计数reference count就加1,每一次析构就减1。再最后一个shared_ptr析构的时候,内存才会被释放。
  • shared_ptr共享被管理对象,同一时刻可以有多个shared_ptr拥有对象的所有权,当最后一个 shared_ptr对象销毁时,被管理对象自动销毁。
图 1

3.1.1 基本用法和函数

shared_ptr的初始化

// 初始化的三种方式,优选第1 和第 2种,因为 make_shared是 构造函数,更高效
auto s = make_shared < int > ( 100 );
shared_ptr < int > s = make_shared < int > ( 100 );
shared_ptr < int > sp1 ( new int ( 100 ));
//不能将一个原始指针直接赋值给一个智能指针,例如,下面这种方法是错误的:
std::shared_ptr < int > p = new int ( 1 );

shared_ptr的常用函数 

  • s.get():              功能:返回shared_ptr中保存的裸指针;
  • s.use_count() :功能:返回shared_ptr 的强引用计数;
  • s.unique() :      功能:若use_count() 1 ,返回 true ,否则返回 false
  • s.reset(…):       功能:重置shared_ptr
    • reset( )不带参数时,若智能指针s是唯一指向该对象的指针,则释放,并置空。若智能指针P不是唯一指向该对象的指针,则引用计数减少1,同时将P置空。
    • reset( )带参数时,若智能指针s是唯一指向对象的指针,则释放并指向新的对象。若P不是唯一的指针,则只减少引用计数,并指向新的对象。如:

auto s = make_shared < int > ( 100 );
s . reset ( new int ( 200 ));
获取原始指针 get
std::shared_ptr < int > ptr ( new int ( 1 ));
int * p = ptr . get (); //
delete p ;                         // 不小心释放  就会造成double free错误
p.get() 的返回值就相当于一个裸指针的值​​​​​​​,谨慎使用p.get() 的返回值
  • 不要保存p.get()的返回值 ,无论是保存为裸指针还是shared_ptr都是错误的
  • 保存为裸指针不知什么时候就会变成空悬指针,保存为shared_ptr则产生了独立指针
  • 不要delete p.get()的返回值 ,会导致对一块内存delete两次的错误

指定删除器

如果用shared_ptr管理非new对象或是没有析构函数的类时,应当为其传递合适的删除器。

#include <iostream>
#include <memory>

using namespace std;

void DeleteIntPtr(int *p) {
    cout << "call DeleteIntPtr" << endl;
    delete p;
}

int main()
{
    std::shared_ptr<int> p(new int(1), DeleteIntPtr);
    return 0;
}
p 的引用计数为 0 时,自动调用删除器 DeleteIntPtr 来释放对象的内存。删除器可以是一个 lambda 表达式,上面的写法可以改为:
std::shared_ptr < int > p ( new int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值