C++智能指针shared_ptr

         每种智能指针都是以类模版的方式实现的,shared_ptr<T>(其中T表示指针指向的具体数据类型)的位于<memory>头文件。  

        shared_ptr是C++11提供的一种智能指针类,它可以在任何地方不使用时自动删除相关指针,从而帮助彻底解决内存泄露和悬空指针的问题。不同的shared_pre对象可以与相同的指针相关联,且在内部使用引用计数机制。

       每个shared_ptr对象的内部指向两个内存位置:指向对象的指针;用于控制引用计数数据的指针。

1.创建智能指针

       shared_ptr<T>类模板中,提供了多种实用的构造函数,有以下几种方式创建智能指针

1)不传实参,创建空智能指针

shared_ptr<int> p1;

2)传入空指针nullptr,创建智能指针

shared_ptr<int> p2(nullptr);

空的shared_ptr指针,其初始引用计数是0,不是1

3)创建智能指针时,明确其指向

shared_ptr<int> p3(new int(10));

创建了一个shared_ptr智能指针,其指向一块存有10这个int类型数据的堆内存空间

C++11标准中还提供了make_shared<T>模版函数,可以用于初始化shared_ptr智能指针

shared_ptr<int> p3=make_shadre<int>(10);

这2种方式创建的P3是相同的

----

shared_ptr<T>模板提供拷贝构造函数、移动构造函数

4)使用拷贝构造函数

shared_ptr<int> p4(p3);
shared_ptr<int> p4=p3;

p3和p4都是shared_ptr类型的智能指针,因此可以用p3来初始化P4,由于p3是左值,因此会调用拷贝构造函数。如果p3为空智能指针,则p4也为空智能指针,其引用计数初始值为0;反之,则表明p4和p3指向同一块堆内存,同时该堆空间的引用计数会加1

注意:同一个普通指针不能同时为多个shadre_ptr对象赋值,否则会导致程序发生崩溃

int *ptr=new int;
shared_ptr<int> p1(ptr);
shared_ptr<int> p2(ptr);/错误

5)使用移动构造函数

shared_ptr<int> p5(move(p4));
shared_ptr<int> p5=move(p4);

对于move(p4)而言,该函数会强制将p4转换成对应的右值,因此初始化p5调用的是移动构造函数。和拷贝构造函数不同,用move(p4)初始化p5,会使得p5拥有p4的堆内存,而p4则变成了空智能指针

6)使用reset()

reset有两个操作,reset()会使引用计数减1;调用reset(new xxx())重新赋值时,智能指针首先生成新对象,然后将旧对象的引用计数减1(如果发现引用计数为0,则析构旧对象),然后重新将对象的指针交给智能指针

shared_ptr<int> p5(new int(9));
cout<<*p5<<endl;
p5.reset(new int(11));
cout<<*p5<<endl;

7)在初始化shared_ptr智能指针时,可以自定义所指向的堆内存的释放规则,这样堆内存的引用计数为0时,会优先调用我们自定义的释放规则。

在某些场景下,自定义释放规则很有必要,比如,对于申请的动态数组来说,shared_ptr指针默认的释放规则是不支持释放数组的,只能自定义对应的释放规则,才能正确地释放所申请的堆内存

对于申请的动态数组,释放规则可以使用C++11标准中提供的default_delete<T>模板类,也可以自定义释放规则

//方式1:
shared_ptr<int> p6(new int[10],default_delete<int[]>());

方式2:
void deleteInt(int *p)
{
   delete[] p;
}

shared_ptr<int> p7(new int[10],deleteInt);

 同时,借助Lambda表达式,还可以像如下进行初始化,效果是一样的

shared_ptr<int> p7(new int[10],[](int *p){delete[] p;});

2.shared_ptr<T>模板类提供的成员方法

 1)operator=()

重载赋值号,使得同一类型的shared_ptr智能指针可以相互赋值

2)operator*()

重载*号,获取当前shared_ptr智能指针对象指向的数据

3)operator->()

重载->号,当智能指针指向的数据类型为自定义的结构体时,通过->运算符可以获取其内部的指定成员

4)swap()

交换两个相同类型的shared_ptr智能指针的内容

5)reset()

当函数没有实参时,该函数会使当前shared_ptr所指堆内容的引用计数减1,同时将当前对象重置为一个空指针;当为函数传递一个新申请的堆内存时,则调用该函数的shared_ptr对象会获得该存储空间的所有权,并且引用计数的初始值为1。

6)get()

获得shared_ptr对象内部包含的普通指针

7)use_count()

返回当前shared_ptr对象(包括它)指向相同的所有shared_ptr对象的数量

8)unique()

判断当前shared_ptr对象指向的堆内存,是否不再有其他shared_ptr对象指向它

9)operator bool()

判断当前shared_ptr对象是否为空智能指针,如果是空指令,返回false,否则返回true

如下面是一个shared_ptr的例子

#include <iostream>
#include<memory.h>
using namespace  std;
class A
{
private:
    int a;
    int b;
public:
    A(int x,int y)
    {
        a=x;
        b=y;
        cout<<"执行了构造函数"<<endl;
    }
    ~A()
    {
        cout<<"执行了析构函数"<<endl;
    }
    void func()
    {
        cout<<"a="<<a<<" b="<<b<<endl;
    }
};
int main() {
    std::cout << "Hello, World!" << std::endl;
    shared_ptr<int> p1(new int(10));
    shared_ptr<int> p2(p1);
    cout<<*p2<<endl;
    p1.reset();
    if(p1)
        cout<<"p1不为空"<<endl;
    else
        cout<<"p1为空"<<endl;
    cout<<*p2<<endl;
    cout<<p2.use_count()<<endl;


    cout<<"另一个test"<<endl;
    shared_ptr<A> p3(new A(3,5));
    p3->func();


    shared_ptr<A> p4(p3);
    cout<<"p3的use_count() "<<p3.use_count()<<endl;
    cout<<"p4的use_count() "<<p4.use_count()<<endl;
    cout<<p3.unique()<<endl;
    cout<<p3.operator bool()<<endl;
    cout<<"p3执行reset之后:"<<endl;
    p3.reset();
    cout<<"p3的use_count() "<<p3.use_count()<<endl;
    cout<<"p4的use_count() "<<p4.use_count()<<endl;

    cout<<p3.unique()<<endl;
    cout<<p3.operator bool()<<endl;

    p4.reset();
    cout<<"p4执行reset之后:"<<endl;
    cout<<p3.unique()<<endl;
    cout<<p4.unique()<<endl;
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值