首页 > 编程语言 >C++ 四种智能指针详解

C++ 四种智能指针详解

时间:2022-12-29 16:08:35浏览次数:40  
标签:cout void C++ 详解 shared unique ptr 指针


  • 智能指针出现的原因:主要解决的是堆内存分配释放,忘记释放内存引发的内存泄漏问题,智能指针最主要的事情就是让程序员无需去注意内存释放,内存释放的问题放在智能指针内部进行处理。
  • 智能指针有四种,包括​​auto_ptr​​​,​​shared_ptr​​​,​​unique_ptr​​​,​​weak_ptr​​​,其中​​auto_ptr​​已经被C++11废弃,所以放在最后介绍。

unique_ptr


unique_ptr的几个重要特性

  • 1.两个unique_ptr不能指向一个对象,即unique_ptr不能共享它所管理的对象,这句话个人的理解的,unique_ptr无法赋值指针到另一个指针,让他们指向同一个对象。
    简单的示例代码:
class A{
public:
A(){
cout << "demo"<< endl;
}
void B(){
cout << "测试" << endl;
}
};

void unique_ptr_use()
{
unique_ptr<A> A_ptr(new A());
A_ptr->B();
cout << A_ptr << endl;
unique_ptr<A> demo = A_ptr; //此时编译错误,无法通过赋值的方式传递指针地址,即与demo共享同一块内存
}

由上面代码可以看出,编译​​unique_ptr<A> demo = A_ptr​​​会报错,因为​​unique_ptr​​是只能单独享有对对象的独有权。

另外,unique_ptr无法通过赋值的形式创建内存对象,即:

C++ 四种智能指针详解_赋值


这种方式也是错误的。

  • 2.提前释放unique_ptr对象可以通过​​reset方法进行重置​​ 示例代码:
void unique_ptr_use()
{
unique_ptr<A> A_ptr(new A());
A_ptr->B();
cout << A_ptr << endl;
A_ptr.reset();
cout << A_ptr << endl;
}

运行结果:

C++ 四种智能指针详解_赋值_02


可以看出:

通过reset方法 可以直接删除原始指针,并且重置为空。

  • 3.我们可以通过转移所有权的方式,来使另一个指针拥有原先unique_ptr的地址
    示例代码:
void unique_ptr_use()
{
unique_ptr<A> A_ptr(new A());
A_ptr->B();
cout << A_ptr << endl;
unique_ptr<A>BB = std::move(A_ptr);
cout << A_ptr << endl;
cout << BB << endl;
}

运行结果:

C++ 四种智能指针详解_#include_03


通过​​std::move()​​方法,将A_ptr的对象转移到BB上面,A_ptr指针为空,BB拥有A_ptr指向的地址。

  • ​release()​​​方法会释放原有的原始指针,但是不会删除原先的指针,删除原先的指针需要通过​​reset()​​​方法
    示例代码:
void unique_ptr_use()
{
unique_ptr<A> A_ptr(new A());
A_ptr->B();
cout << A_ptr << endl;
A * nn = A_ptr.release();
cout << nn << endl;
cout << A_ptr << endl;
delete nn;
nn = nullptr;
cout << nn << endl;
}

运行结果:

C++ 四种智能指针详解_示例代码_04

  • 知识点:使用​​delete​​删除指针,编译器只会释放原先指向的内存空间,不会释放指针本身,所以需要通过设置指针为空来删除指针本身!!!
  • 4.使用get方法 获取关联的指针对象
void unique_ptr_use()
{
unique_ptr<A> A_ptr(new A());
A_ptr->B();
A * m = A_ptr.get();
cout << "11---" << m << endl;
cout << A_ptr << endl;
A * nn = A_ptr.release();
cout << nn << endl;
cout << A_ptr << endl;
delete nn;
nn = nullptr;
cout << nn << endl;
}

运行结果:

C++ 四种智能指针详解_示例代码_05


shared_ptr


​shared_ptr​​​可以实现多个对象共同托管一个指针,这个是​​unique_ptr​​​做不到的。当曾经的托管对象接触对其托管时,系统会自动执行​​delete p​​释放内存,这样保证了内存不会泄漏。

  • ​shared_ptr​​​:可以查看赋值对象的个数,因为可以多个对象共同托管,所以个数需要获得,已经内置了一个​​use_count()​​方法返回当前可以操作该指针的对象个数。
  • 示例代码:
void shared_ptr_use()
{
shared_ptr<A> mm = make_shared<A>();
mm->B();
cout <<"mm value:" << mm << endl;
shared_ptr<A> ff(mm);
cout << "ff value:" << ff << endl;
cout << "个数为" << ff.use_count() << endl;
mm.reset();//重置
cout <<"now ff:"<< ff << endl;
cout << "个数为" << ff.use_count() << endl;
cout <<"now mm:"<< mm << endl;
}
  • 运行结果:

weak_ptr


  • 首先,​​weak_ptr​​​不能直接定义一个对象类,需要配合​​shared_ptr​​​进行使用,通过​​shared_ptr​​传指针地址给它。
  • ​weak_ptr​​​主要解决的一个问题是​​shared_ptr​​相互引用无法释放内存的问题。
  • 实例代码:
class B;
class A{
public:
A(){
cout << "A init!" << endl;
}
~A(){
cout << "A Destroy" << endl;
}
void set_quote_ptr(shared_ptr<B>mm)
{
m_b = mm;
}
private:
shared_ptr<B> m_b;
};

class B{
public:
B(){
cout << "A init!" << endl;
}
~B(){
cout << "A Destroy" << endl;
}
void set_quote_ptr(shared_ptr<A>mm)
{
m_a = mm;
}
private:
shared_ptr<A> m_a;
};

void test_ptr()
{
shared_ptr<A>a_ptr = make_shared<A>();
shared_ptr<B>b_ptr = make_shared<B>();
a_ptr->set_quote_ptr(b_ptr);
b_ptr->set_quote_ptr(a_ptr);
cout << "a count" << a_ptr.use_count() << endl;
cout << "b count" << b_ptr.use_count() << endl;
}

int main()
{
test_ptr();
system("pause");
return 0;
}

此时他们之前存在相互引用,但是已经方法已经返回了还没稀释

运行结果:

C++ 四种智能指针详解_示例代码_06


解释原因可以参考:​​https://blog.csdn.net/albertsh/article/details/82286999#commentBox​​:解释了无法析构的原因,这里简单介绍一下。主要是相互引用时,导致引用记数无法为0;所以无法调用函数进行析构。

  • 接下来解决的方案,是使用​​weak_ptr​​​来替代其中一个​​shared_ptr​​,因为这样赋值的话,不会引发计数变化,修改完的代码如下:
#include "stdafx.h"
#include <iostream>
#include <memory>
using namespace std;

class B;
class A{
public:
A(){
cout << "A init!" << endl;
}
~A(){
cout << "A Destroy" << endl;
}
void set_quote_ptr(shared_ptr<B>mm)
{
m_b = mm;
}
private:
weak_ptr<B> m_b;
};

class B{
public:
B(){
cout << "A init!" << endl;
}
~B(){
cout << "A Destroy" << endl;
}
void set_quote_ptr(shared_ptr<A>mm)
{
m_a = mm;
}
private:
weak_ptr<A> m_a;
};

void test_ptr()
{
shared_ptr<A>a_ptr = make_shared<A>();
shared_ptr<B>b_ptr = make_shared<B>();
a_ptr->set_quote_ptr(b_ptr);
b_ptr->set_quote_ptr(a_ptr);
cout << "a count" << a_ptr.use_count() << endl;
cout << "b count" << b_ptr.use_count() << endl;
}

int main()
{
test_ptr();
system("pause");
return 0;
}

运行结果:

C++ 四种智能指针详解_示例代码_07


可以明显的看出,已经被析构了。

  • weak_ptr还有两个主要的方法​​lock()​​​和​​expired()​​,这边简单介绍一下
  • ​expired​​​主要判断赋值给他的​​shared_ptr​​对象是否还在,在的话返回1,不在的话返回0
  • ​lock()​​​返回赋值它的​​shared_ptr​​​对象。
    实例代码:
// Weak_Ptr_Use.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <memory>
using namespace std;

class B;
class A{
public:
A(){
cout << "A init!" << endl;
}
~A(){
cout << "A Destroy" << endl;
bool is_fired = m_b.expired();
cout << "endl:" << is_fired << endl;
}
void set_quote_ptr(shared_ptr<B>mm)
{
m_b = mm;
}
weak_ptr<B> m_b;
};

class B{
public:
B(){
cout << "B init!" << endl;
}
~B(){
cout << "B Destroy" << endl;
}
void set_quote_ptr(shared_ptr<A>mm)
{
m_a = mm;
}
void show()
{
cout << "调用B方法测试" << endl;
}
private:
weak_ptr<A> m_a;
};

void test_ptr()
{
shared_ptr<A>a_ptr = make_shared<A>();
shared_ptr<B>b_ptr = make_shared<B>();
a_ptr->set_quote_ptr(b_ptr);
b_ptr->set_quote_ptr(a_ptr);
weak_ptr<B> b_weak_ptr = b_ptr;
if (b_weak_ptr.expired())
{
b_weak_ptr.lock()->show();
}
cout << "a count" << a_ptr.use_count() << endl;
cout << "b count" << b_ptr.use_count() << endl;
}

int main()
{
test_ptr();
system("pause");
return 0;
}

运行结果:

C++ 四种智能指针详解_#include_08


auto_ptr


  • 简单来说,auto_ptr和unique_ptr比较像,但是auto_ptr具备拷贝语义,unique_ptr只有转移所有权的方式
    代码示例:
// Weak_Ptr_Use.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <memory>
using namespace std;

class A
{
public:
A(){
cout << "A Init" << endl;
}
~A()
{
cout << "A Destory" << endl;
}
void show()
{
cout << "demo" << endl;
}
};

void test_auto_demo()
{
unique_ptr<A> mma(new A());
cout << mma << endl;
auto_ptr<A> A_PTR(new A());
auto_ptr<A>mm = A_PTR; //实质和std::move()语义一样。
cout << mm.get() << endl;
cout << A_PTR.get() << endl;
A_PTR->show();
}

int main()
{
test_auto_demo();
system("pause");
return 0;
}

运行结果:

C++ 四种智能指针详解_赋值_09


造成在这个的原因是​​auto_ptr<A>mm = A_PTR; //实质和std::move()语义一样。​​ 这边A_PTR已经把所有权转给mm,此时A_PTR为空指针,空指针必然报错。。

所以​​unique_ptr​​比​​auto_ptr​​更加安全,实质上个人觉得应该是编译器对​​unique_ptr​​的处理更加灵活。


智能指针的应用场景



标签:cout,void,C++,详解,shared,unique,ptr,指针
From: https://blog.51cto.com/u_15906863/5978158

相关文章

  • 利用WindowsAPI创建窗体(c++)
    代码://回调函数LRESULTCALLBACKWinProc(HWNDhWnd,UINTuMsg,WPARAMwParam,LPARAMlParam){switch(uMsg){caseWM_CREATE:break;caseWM_DESTROY:{P......
  • C++ #define参数问题
    今天看代码的时候发现一个问题,记录一下#include<iostream>#defineAddData(a,b)a=b+a;b=a+d;d=a+b;usingnamespacestd;intmain(){intd=2;inta=2......
  • C++ zip压缩库使用
    这个压缩库,主要是用来解压和压缩相关文件使用,好处就是引入比较方便,而且极其易使用,方便用户操作。首先是引入这四个文件,相关代码如下:首先是​​zip.h​​头文件#ifndef_zip_......
  • Windows进程通信之共享内存通信(C++)
    首先是概念:​​https://baike.baidu.com/item/%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98/2182364?fr=aladdin​​这是比较官方的解释在我的理解,共享内存通信指的是,一个进程开......
  • windows 根据父进程pid查找所有子进程id(C++)
    直接上代码:大家直接调用即可#include<iostream>#include<Windows.h>#include<tlhelp32.h>#include<string>#include<vector>usingnamespacestd;vector<DWORD>GetPro......
  • Hook Windows API调用 C++
    //dllmain.cpp:定义DLL应用程序的入口点。#include"pch.h"//olddatatypedefBOOL(WINAPI*pProcessInternalW)(HANDLEhToken,LPCWSTRAppName,LPWSTRCmdLine,......
  • C++数据结构01--顺序线性表实现
    今天正好又是很闲,就简单实现一下数据结构里面的顺序线性表玩一下,后面有时间再慢慢把后面几种数据结构实现一下玩一下。顺序线性表,就是在连续内存中元素按内存地址顺序排列的......
  • C++:OutputDebugString作用(以VS2019为演示例子)
    上最简单的代码:#include<iostream>#include<Windows.h>usingnamespacestd;intmain(){OutputDebugString(L"输出调DD试信息123");cout<<"HelloWorld!\n";}......
  • memcpy 作用(C++)
    memcpy就是拷贝字节数例如:memcpy((void*)OpenProcessaddr,OldByte,5);这段代码的意思是从OldByte的地址当中,取前5个字节,拷贝到openprocessaddr的内存地址上 ......
  • C++数据结构03--静态链式线性表的实现
    头文件://静态链表头文件#include"stdafx.h"usingnamespacestd;#defineMAXSIZE250typedefintElemType;typedefstruct{ElemTypedata;intcur;//存在next的指针......