C++智能指针

简介: 裸智能指针有很多不好,比如容易导致内存泄漏、同一资源释放多次等。因此在C++11库里提供了很多的智能指针,他们分为两类一个是不带引用计数的智能指针:auto_ptr,scoped_ptr、unique_ptr;还有一个是带引用计数的智能指针:shared_ptr、weak_ptr。

1.智能指针的实现原理:

定义一个对象的时候会在构造函数里将我传入的指针的值为智能指针对象底层管理的指针初始化,在出了大括号后调用析构函数,释放指针所管理的资源并将指针置为空。



2.智能指针的分类与实现原理:

(1)不带引用计数的智能指针:auto_ptrscoped_ptrunique_ptr

auto_ptr:将传入的对象的底层指针给我本对象的底层指针、并将被拷贝(赋值)对象的底层指针置空。这样对于用户是不友好的,因为用户传入一个对象根本就不知道传入的对象将会失效。

image.png

scoped_ptr:将左值拷贝构造与左值拷贝赋值给delete,从根本上杜绝了两根指针指向同一份资源带来资源泄漏问题。(scoped_ptr好像visual studio2023不支持,所以这边没贴图片了)

unique_ptr(最常用):将左值拷贝构造与左值拷贝赋值给delete,添加右值拷贝构造与右值拷贝赋值。这样对于用户是友好的,因为用户想传参,比如得move一下,此时用户是知道我传入的对象即将失效。

image.png


(2)带引用计数的智能指针:shared_ptrweak_ptr

shared_ptr:增加一个管理引用计数的对象作为成员指针,这个引用计数的对象所对应的类底层是对引用计数的封装

下面我们通过代码演示它的实现原理:

#include <iostream>usingnamespacestd;
//对资源进行引用计数的类template<typenameT>classRefCnt{
public:
RefCnt(T*ptr=nullptr) :mptr(ptr)
    {
if (mptr!=nullptr)
mcount=1;
    }
voidaddRef()
    {
mcount++;//增加资源的引用计数    }
intdelRef()
    {
return--mcount;
    }
private:
T*mptr;
intmcount;
};
template<typenameT>classCSmartPtr{
public:
CSmartPtr(T*ptr=nullptr) :mptr(ptr)
    {
mpRefCnt=newRefCnt<T>(mptr);
    }
~CSmartPtr()
    {
if (0==mpRefCnt->delRef())
        {
deletemptr;
mptr=nullptr;
        }
    }
CSmartPtr(constCSmartPtr<T>&src) :mptr(src.mptr), mpRefCnt(src.mpRefCnt)
    {
if (mptr!=nullptr)
        {
mpRefCnt->addRef();
        }
    }
CSmartPtr<T>&operator=(constCSmartPtr<T>&src)
    {
if (this==&src)
        {
return*this;
        }
if (0==mpRefCnt->delRef())
        {
deletemptr;
        }
mptr=src.mptr;
mpRefCnt=src.mpRefCnt;
mpRefCnt->addRef();
return*this;
    }
T&operator*()
    {
return*mptr;
    }
T*operator->()
    {
returnmptr;
    }
private:
T*mptr;//指向资源的指针RefCnt<T>*mpRefCnt;//指向该资源引用计数对象的指针};
intmain(void)
{
CSmartPtr<int>ptr1(newint);
CSmartPtr<int>ptr2=ptr1;
return0;
}              

在这段代码中,给每一个对象资源,就会匹配一个引用计数对象指针,并将底层的引用计数置为1。当智能指针使用资源的时候,引用计数+1;当智能指针不使用资源的时候,引用计数-1;引用计数等于0的时候开始释放资源。

weak_ptr:只能观察资源,不能改变资源的引用计数,不能访问资源

同样的我们通过一段代码来演示weak_ptr的用法。

#include <iostream>#include <memory>usingnamespacestd;
classB;
classA{
public:
A()
    {
cout<<"A()"<<endl;
    }
~A()
    {
cout<<"~A()"<<endl;
    }
voidtestA()
    {
cout<<"非常好用的方法"<<endl;
    }
weak_ptr<B>_ptrb;
};
classB{
public:
B()
    {
cout<<"B()"<<endl;
    }
~B()
    {
cout<<"~B()"<<endl;
    }
voidfunc()
    {
shared_ptr<A>ps=_ptra.lock();
if (ps!=nullptr)
        {
ps->testA();
        }
    }
weak_ptr<A>_ptra;
};
intmain(void)
{
shared_ptr<A>pa(newA());
shared_ptr<B>pb(newB());
pa->_ptrb=pb;
pb->_ptra=pa;
cout<<pa.use_count() <<endl;
cout<<pb.use_count() <<endl;
pb->func();
return0;
}

在这一段代码中,weak_ptr的引用并不会改变对象资源的引用计数,如果想让它能够访问资源需要调用.lock()方法把它提升成强智能指针

这种手法也被用来解决shared_ptr的交叉引用问题以及多线程访问共享对象的线程安全问题。在后面我们会有两期分别对这两个问题进行讲解。

相关文章
|
1月前
|
C++
【C++】智能指针
【C++】智能指针
|
16天前
|
C++
C++(十八)Smart Pointer 智能指针简介
智能指针是C++中用于管理动态分配内存的一种机制,通过自动释放不再使用的内存来防止内存泄漏。`auto_ptr`是早期的一种实现,但已被`shared_ptr`和`weak_ptr`取代。这些智能指针基于RAII(Resource Acquisition Is Initialization)原则,即资源获取即初始化。RAII确保对象在其生命周期结束时自动释放资源。通过重载`*`和`-&gt;`运算符,可以方便地访问和操作智能指针所指向的对象。
|
16天前
|
C++
C++(九)this指针
`this`指针是系统在创建对象时默认生成的,用于指向当前对象,便于使用。其特性包括:指向当前对象,适用于所有成员函数但不适用于初始化列表;作为隐含参数传递,不影响对象大小;类型为`ClassName* const`,指向不可变。`this`的作用在于避免参数与成员变量重名,并支持多重串联调用。例如,在`Stu`类中,通过`this-&gt;name`和`this-&gt;age`明确区分局部变量与成员变量,同时支持链式调用如`s.growUp().growUp()`。
|
28天前
|
存储 安全 C++
C++:指针引用普通变量适用场景
指针和引用都是C++提供的强大工具,它们在不同的场景下发挥着不可或缺的作用。了解两者的特点及适用场景,可以帮助开发者编写出更加高效、可读性更强的代码。在实际开发中,合理选择使用指针或引用是提高编程技巧的关键。
23 1
|
1月前
|
安全 NoSQL Redis
C++新特性-智能指针
C++新特性-智能指针
|
1月前
|
编译器 C++
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
|
1月前
|
存储 安全 编译器
C++入门 | auto关键字、范围for、指针空值nullptr
C++入门 | auto关键字、范围for、指针空值nullptr
49 4
|
2月前
|
存储 安全 C++
浅析C++的指针与引用
虽然指针和引用在C++中都用于间接数据访问,但它们各自拥有独特的特性和应用场景。选择使用指针还是引用,主要取决于程序的具体需求,如是否需要动态内存管理,是否希望变量可以重新指向其他对象等。理解这二者的区别,将有助于开发高效、安全的C++程序。
26 2
|
2月前
|
存储 安全 C++
浅析C++的指针与引用
虽然指针和引用在C++中都用于间接数据访问,但它们各自拥有独特的特性和应用场景。选择使用指针还是引用,主要取决于程序的具体需求,如是否需要动态内存管理,是否希望变量可以重新指向其他对象等。理解这二者的区别,将有助于开发高效、安全的C++程序。
23 3
|
30天前
|
存储 C++
c++学习笔记06 指针
C++指针的详细学习笔记06,涵盖了指针的定义、使用、内存占用、空指针和野指针的概念,以及指针与数组、函数的关系和使用技巧。
29 0