C++ 智能指针 : auto_ptr 、unique_ptr、 shared_ptr、 weak_ptr

1、智能指针设计初衷:

        智能指针实际是类,超过类的作用域后,析构函数会自动回收资源,为程序员管理申请的堆内存,避免内存泄漏

2、C++ 智能指针种类: 

auto_ptr

(C++98 的⽅案,C11 已抛弃)采⽤所有权模式。auto_ptr构造时取得某个对象的所有权,在析构时释放该对象。我们实际上是创建一个auto_ptr<Type>类型的局部对象,该局部对象析构时,会将自身所拥有的指针空间释放,所以不会有内存泄露。auto_ptr不支持new 数组。

注意:不要使用auto_ptr 作为函数入参因为函数的形参其实是拷贝,然而智能指针拷贝的过程,会导致其拥有权发生转移,你传入的实参拥有权会转移到拷贝后的形参上,形参在函数运行的生命周期结束后,就会析构,导致你之前实参拥有的(主程序的对象、内存)内存被释放,导致致命的执行错误。

结论:如果必须需要使用智能指针作为函数入参,使用const 引用

#include <iostream>
#include <memory> 
using namespace std;

int main()
{
    //auto_ptr 通过构造函数初始化
    int*ptr1 = new (std::nothrow)int(4);
    if (nullptr == ptr1)
    {
        cout<<"new failed !"<<endl;
        return -1;
    }

    auto_ptr<int> a_ptr1(ptr1);
    auto_ptr<int> a_ptr2(new int(5));
    cout << "a_ptr1 data : "<<*a_ptr1 <<endl;
    cout << "a_ptr2 data : "<<*a_ptr2 <<endl;

    //一块内存只能由一个auto_ptr独享,拷贝构造或赋值时都会发生拥有权转移
    //拷贝构造,a_ptr1失去对ptr1内存的所有权,a_ptr3拥有,负责内存的销毁
    auto_ptr<int> a_ptr3(a_ptr1);

    //赋值
    a_ptr2 = a_ptr3;
    //cout << "拷贝构造后 a_ptr1 data : "<<*a_ptr1 <<endl;
    cout << "赋值后 a_ptr2 data : "<<*a_ptr2 <<endl;
    //cout << "赋值后 a_ptr3 data : "<<*a_ptr3 <<endl;

    //智能指针会默认初始化为0
    auto_ptr<int> a_ptr4;

    //禁止一个对象(内存)被多个auto_ptr拥有
    /* int *data = new (std::nothrow)int(5);
    auto_ptr<int> a_ptr5 = auto_ptr<int>(data);
    auto_ptr<int> a_ptr6 = auto_ptr<int>(data);
    cout << "a_ptr5 data : "<<*a_ptr5 <<endl;
    cout << "a_ptr6 data : "<<*a_ptr6 <<endl; */

    //常用函数
    //get()获取auto_ptr拥有的内存(对象)的地址
    int *data1 =  new (std::nothrow)int(5);
    auto_ptr<int> a_ptr7(data1);
    cout << "the add of data1: " << data1 << endl;
    cout << "the get() return of a_ptr7: " << a_ptr7.get() << endl;

    //reset 重置auto_ptr拥有的内存(对象),重置的过程会释放auto_ptr先拥有的内存int(5)
    cout << "the data of a_ptr7: " << *a_ptr7 << endl;
    a_ptr7.reset(new (std::nothrow)int(6));
    cout << "the data of a_ptr7 after reset: " << *a_ptr7 << endl;

    return 0;
    
}

unique_ptr

unique_ptr 实现独占式拥有或严格拥有概念,保证同⼀时间内只有⼀个智能指针可以指向该对 象。它对于避免资源泄露特别有⽤。

#include <iostream>
#include <memory> 
using namespace std;

int main()
{

    /* unique_ptr */
    int *p = new int(5);
    unique_ptr<int>p1(p);
    //std::unique_ptr<int>p2=p1;// 编译会出错
    //move转移所有权, 现在那块内存归p3所有, p1成为无效的指针.
    unique_ptr<int>p3=move(p1);
    cout << "the add of p: " << p <<" | "<<  " the data of p: " << *p << endl;
    cout << "the add of p3: " << p3.get() <<" | "<< " the data of p3: " << *p3 <<endl;
    //reset释放内存.
    p3.reset();
    //无效
    //p1.reset();

    //默认初始为nullptr
    unique_ptr<int>p4;
    cout << "the add of p4 : " << (p4 ? "not nullptr" : "nullptr") << endl;

    //release释放智能指针的内存拥有权
    int *a = new int(4);
    p4 = (unique_ptr<int>)(a);
    int *p5 = p4.release();
    cout << "the add of a: " << a <<" | "<< "the data of a: " << *a <<endl;
    cout << "the add of p5: " << p5 <<" | "<< "the data of p5: " << *p5 <<endl;
    delete p5;
    p5 = nullptr;

    //swap交换内存
    unique_ptr<int> p6(new int (6)); 
    unique_ptr<int> p7(new int (7));
    p6.swap(p7);
    cout << "the data of p6: " << *p6 << " | " <<"the data of p7: " << *p7 << endl;

    return 0;
    
}

shared_ptr

共享型智能指针,一块内存可被多个shared_ptr 引用,内部采用引用计数管理,计数为0时,则删除智能指针,回收资源。

注意:

1、不要使用同一个原始指针构造 shared_ptr,如果需要构建多个shared_ptr管理同一块内存,使用一个已存在的shared_ptr 进行创建。

2、shared_ptr 不能相互引用,会导致引用计数无法下降到0,资源无法被回收,造成内存泄漏

#include <iostream>
#include <memory> 
using namespace std;

int main()
{
    
    /* shared_ptr */
    //使用 make_shared 创建空对象
	shared_ptr<int> sha_p1 = make_shared<int>();
    *sha_p1 = 1;

    //use_count 查看内存引用计数
    cout << "the use count = " << sha_p1.use_count() << endl; //1

    //无参reset 计数重置为0
    sha_p1.reset();
    cout << "the use count = " << sha_p1.use_count() << endl; //0

    //有参reset 计数为1
    sha_p1.reset(new int(2));
    cout << "the use count = " << sha_p1.use_count() << endl; //1

    //置nullptr 计数为0
    sha_p1 = nullptr;
    cout << "the use count = " << sha_p1.use_count() << endl; //0

    //不要用原始指针初始化多个智能指针
    int *num = new int(3);
    shared_ptr<int> sha_p2(num);
    
    shared_ptr<int> sha_p3(sha_p2);  // 正确使用方法
    shared_ptr<int> sha_p4(num);     // 不推荐
    //假如使用原始指针num创建了sha_p2,sha_p4,当sha_p2超出作用域时会调用
    //delete释放num内存,此时num成了悬空指针,当sha_p4超出作用域再次delete的时候就可能会出错

    cout << "sha_p2 use count = " << sha_p2.use_count() << endl; // 输出 2
    cout << "sha_p3 use count = " << sha_p3.use_count() << endl; // 输出 2
    cout << "sha_p4 use count = " << sha_p4.use_count() << endl; // 输出 1

    return 0;

}

weak_ptr

weak_ptr 是为了配合 shared_ptr 而引入的一种智能指针,可以解决shared_ptr 循环引用的问题,weak_ptr,由于是弱共享,weak_ptr 的创建并不会影响 shared_ptr 的引用计数值。

#include <iostream>
#include <memory> 
using namespace std;

class ClassB;
 
class ClassA
{
public:
 ClassA() { cout << "ClassA Constructor Success" << endl; }
 ~ClassA() { cout << "ClassA Destructor Success" << endl; }
 weak_ptr<ClassB> pb; // 在A中引用B
};
 
class ClassB
{
public:
 ClassB() { cout << "ClassB Constructor Success" << endl; }
 ~ClassB() { cout << "ClassB Destructor Success" << endl; }
 weak_ptr<ClassA> pa; // 在B中引用A
};

int main()
{
   
    /* weak_ptr*/
    shared_ptr<ClassA> ca_ptr = make_shared<ClassA>();
    shared_ptr<ClassB> cb_ptr = make_shared<ClassB>();
    ca_ptr->pb = cb_ptr;
    cb_ptr->pa = ca_ptr;
    cout << "the use count of ca_ptr = " << ca_ptr.use_count() << endl; //1
    cout << "the use count of cb_ptr = " << cb_ptr.use_count() << endl; //1
    //对象A 、B都被析构了

    return 0;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半岛铁盒.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值