【c++】智能指针学习笔记

1. new和delete的配套使用

  • delete和new应配套使用,new分配内存,应使用delete来释放;new []为数组分配内存,则应使用delete []来释放
  • new和delete的配套使用可能出现的问题
    忘记delete内存
    同一块内存释放两次
    使用已经释放的对象

2. 智能指针介绍

  • shared_ptr允许多个指针指向同一个对象;unique_ptr独占所指向的对象;weak_ptr弱引用,指向shared_ptr所指向对象

  • 头文件

    #include <memory>
    
2.1 auto_ptr
  • C98引入,C11中已弃用

  • auto_ptr存在的问题:当使用两个指针指向同一个对象时,程序可能会尝试删除同一个对象两次,即使在进行移动运算符重载(深拷贝)后,已释放对象所有权的指针可能再次访问该对象导致程序奔溃(编译没问题、运行时coredump)

  • auto_ptr成员函数

    get()		// 返回原始指针
    reset()		// 释放资源及所有权;p2(reset(p1))则p2会释放原来对象的所有权
    release()	// 释放对资源的所有权,析构函数没有调用
    
  • auto_ptr判断智能指针是否为空

    if (p.get() == nullptr) {...}
    
  • 访问指针的成员函数:.get() 或 .reset(),通过.访问

  • 访问对象的成员函数:->func(),通过->访问

  • p2 = p1
    p2会接管p1的内存管理权,p1会变成空指针,如果p2原来不为空,会释放原来的资源

2.2 unique_ptr
  • C11引入,用于取代auto_ptr,独享所有权的智能指针

  • unique_ptr如果尝试使用两个指针指向同一对象,在编译期就会报错

  • 而且unique_ptr能和new/new[]一起使用,auto_ptr/shared_ptr只能使用new

  • 无法使两个unique_ptr指向同一个对象。无法进行复制/构造复制赋值操作,可以进行移动构造和移动赋值操作。即不能使用p2=p1,可以使用p2=std::move(p1)

  • 当unique_ptr被删除释放时,会释放它指向的对象

  • 为动态申请的内存提供异常安全

  • 可以将动态申请的内存所有权传递给函数,也可以从函数返回动态申请的内存所有权

  • 可以在容器中保存指针

  • 具有auto_ptr应有的功能

  • unique_ptr成员函数:

    get()		// 返回原始指针
    reset()		// 释放资源及所有权
    release()	// 释放对资源的所有权,析构函数没有调用
    			// release返回的指针通常被用来初始化另一个智能指针或赋值,
    			// 如果赋值给普通指针程序要负责资源的释放,释放内存要使用reset
    swap(p1, p2) // 交换两个智能指针的值
    
  • unique_ptr的使用

    if (p == nullptr) {}	// 判断unique_ptr指针是否为空
    unique_ptr不支持普通拷贝和赋值,但可以通过release和reset转移指针所有权
    unique_ptr<string> p2(p1.release());	// 将所有权从p1转移给p2
    unique_ptr<string> p3(new string("abcde"));
    p2.reset(p3.release());		// p3置空,并返回指针
    					  		// p2释放原来指向的对象,并重新指向p3对象
    unique_ptr不支持=赋值,但作为函数返回值的时候使用了移动构造函数:
    unique_ptr<Test> fun()
    {
    	return unique_ptr<Test>(new Test("789"));
    }
    unique_ptr<Test> p = func();	// 使用了移动构造函数
    
  • p2 = std::move(p1)
    std::move(p1)构造了右值,p1的内存所有权转移给p2但是资源未释放。
    如果p2原来不为空,会释放p2原来的资源。

2.3 shared_ptr
  • 可以被多个指针共享,通过计数机制来表明资源被几个指针共享

  • 可以使用=来赋值,引用次数变化

  • shared_ptr成员函数

    get()		// 返回原始指针
    reset()		// 释放资源及所有权
    swap(p1, p2) // 交换两个智能指针
    use_count()	// 查看资源的所有者数量
    // shared_ptr没有release()成员
    
  • reset()函数说明
    p.reset() 若p是唯一指向对象的shared_ptr,则会释放此对象
    p.reset(q) 若传递了参数内置指针q,会令p指向q,q释放对资源的所有权?

  • 如果p1.use_count()和p2.use_count()都是2;p2.reset()资源不会释放;p1.reset()资源释放

  • p2 = p1;
    p1指向资源的引用次数+1,p2指向的资源引用次数-1

2.4 weak_ptr
  • weak_ptr是用来解决shared_ptr相互引用时的死锁问题

  • 对象的弱引用,不会增加对象的引用计数

  • weak_ptr可以通过lock函数来获得shared_ptr

    Class A {weak_ptr<B> pb;}
    不能使用pa->pb->print()访问B类中成员函数,
    可以使用shared_ptr<B> p = pa->pb.lock(); p->print()来进行访问
    
  • weak_ptr的常用方法

    weak_ptr<T> wp;	// 空weak_ptr指向类型为T的对象
    weak_ptr<T> wp(sp); // 与shared_ptr sp指向相同对象
    wp = p; // p可以是shared_ptr也可以是weak_ptr
    wp.reset(); // 将wp置为空
    wp.use_count(); // 与wp共享对象的shared_ptr的个数
    wp.expired(); // wp.use_count()==0为true,否则为false
    wp.lock(); // 返回指向wp对象的shared_ptr;如果expired返回true返回一个shared_ptr类型的空指针
    

2. 智能指针使用tips

  1. 智能指针的选择

    1. 如果多个指针指向同一个对象,应选择shared_ptr
    2. 如果不需要多个指针指向同一个对象,则可以使用unique_ptr
    3. 如果使用new分配内存,并返回指向该内存的指针,将其返回类型声明为unique_ptr是不错的选择
    4. weak_ptr弱引用不增加对象引用计数,避免shared_ptr智能指针陷阱
    
  2. 创建智能指针时必须提供指针所指向的类型

  3. 默认初始化的智能指针中保存着一个空指针

  4. shared_ptr和unique_ptr都支持的操作

    shared_ptr<T> sp;    unique_ptr<T> up;
    if (p == nullptr)
    *p获得所指向对象
    p.get()返回p所保存的指针
    swap(p1, p2); 或 p2.swap(p1)交换p1和p2的指针
    

    shared_ptr独有的操作

    make_shared<T> (args)	返回shared_ptr,指向类型为T的对象,args为初始化参数
    shared_ptr<T> p(q);		p是q的拷贝,此操作会增加q的计数
    p = q					此操作会递减p的引用计数,递增q的引用计数,如果p引用次数减为0,则释放其管理的内存资源
    p.use_count()			返回与p共享对象的智能指针数量,耗时,主要用于调试
    p.unique()				若p.use_count() == 1返回true,否则返回false
    
    make_shared函数头文件:#include<memory>
    shared_ptr<int> p1 = make_shared<int>(11);
    shared_ptr<string> p2 = make_shared<string>(5,'9');
    shared_ptr<int> p3 = make_shared<int>();			// 不传递任何参数
    
    shared_ptr与new的结合使用:不能显示转换,必须直接初始化
    shared_ptr<int> p1 = new int(1024);		// 错误
    shared_ptr<int> p2(new int(1024));		// 正确,使用了直接初始化形式
    
  5. 不要混合使用普通指针和智能指针

  6. std::move是转移对象的所有权

    std::move可以移动右值,也可以把左值转换为右值,从而实现移动
    可以用来转移unique_ptr的对象所有权
    std::move要有左值承接才能调用移动构造函数

  7. p2 = p1总结

    auto_ptr: p2 = p1
    p2会接管p1的内存管理权,p1会变成空指针,如果p2原来不为空,会释放原来的资源; 如果再使用p1访问对象会导致程序奔溃
    unique_ptr: p2 = p1
    编译报错。只允许一个指针指向对象;
    unique_ptr: p2 = std::move(p1)
    std::move(p1)构造了右值,p1的内存所有权转移给p2但是资源未释放;如果p2原来不为空,会释放p2原来的资源
    shared_ptr: p2 = p1
    p1指向资源的引用次数+1,p2指向的资源引用次数-1,如果减为0则释放资源
    weak_ptr: p2 = p1
    p1可以是shared_ptr也可以是weak_ptr,不会增加p1资源引用计数


参考文章:
智能指针实例详解
智能指针使用tips
C++ Prime Plus

created by shuaixio, 2022.02.20

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值