首页 > 编程语言 >[C++] 初识 智能指针

[C++] 初识 智能指针

时间:2024-08-25 17:23:35浏览次数:9  
标签:std auto C++ 智能 初识 shared ptr 指针

标题:[C++] 初识 智能指针

@水墨不写bug



目录

一、前言

二、智能指针

1. 什么是RAII?

2.智能指针分类

 三、智能指针简介

1.std::auto_ptr

2.std::unique_ptr

3.std::shared_ptr


正文开始:

一、前言

        C++智能指针的出现是有一定的背景的:

        Java有专属的GC(垃圾回收功能),这样一来可以在一定程度上解放解放程序员的关于内存方面的思考与手动设计,但GC等特点也是Java相对于C++效率较低的原因。在使用C++编程时,需要时刻注意内存的管理,但是尽管我们时刻都记得要注意内存的管理逻辑,在有一些场景,内存泄漏时有发生,比如下边这样的一个场景:

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

double div(double a, double b)
{
	if (b == 0)
		throw string("div by zero");
	return a / b;
}
void func()
{
	int* parr1 = new int[10];   // 一
	int* parr2 = new int[10];   // 二

	//...
	double a, b;
	cin >> a >> b;
	cout << div(a,b) << endl;   // 三
	delete[] parr1;
	delete[] parr2;
}
int main()
{
	try {
		func();
	}
	catch (string s)
	{
		cout << s << endl;
	}
	catch (...)
	{
		cout << "unknown err" << endl;
	}
	return 0;
}

        在上述场景中,有三个地方可能会抛出异常:如果一处抛异常——则不用释放空间;如果二处抛异常——则需要只释放parr1;如果三处抛异常——则需要释放parr1和parr2。

        这些逻辑比较复杂,为了处理这些场景下复杂的内存管理,C++引入了智能指针。

二、智能指针

1. 什么是RAII?

           C++中的RAII(Resource Acquisition Is Initialization,资源获取即初始化)是一种资源管理技术,它的核心思想是将资源的获取(Acquisition)与对象的初始化(Initialization)结合起来,并通过对象的生命周期来管理资源的使用期。一旦对象被创建,资源就被自动获取;当对象生命周期结束时(例如,对象被销毁时),其析构函数会自动释放或归还资源

借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:


        1.不需要显式地释放资源。
        2.采用这种方式,对象所需的资源在其生命期内始终保持有效
 

         智能指针的实现思路及原理就是RAII的思想。


2.智能指针分类

         目前常用的智能指针有如下几种:

        std::auto_ptr:C++98版本的库中就提供了auto_ptr的智能指针。(不建议使用)
        std::unique_ptr:unique_ptr的实现原理:简单粗暴的防拷贝。
        std::shared_ptr:C++11中开始提供更靠谱的并且支持拷贝的shared_ptr。

 三、智能指针简介

        其实智能指针的基本原理的实现并不困难,就是把一个指针类中,写好构造和析构就可以正常使用了——当前函数栈桢退出,局部变量就会自动销毁。不同的是不同智能指针对于拷贝构造和赋值重载的处理是不同的,而其他接口的处理基本是相同的。

1.std::auto_ptr

        auto_ptr的实现原理:管理权转移。

        std::auto_ptr是比较老的智能指针类型,它可以拷贝构造,但是拷贝构造不是意味着构造了一个新的指针,而是将管理权转移到了新的指针;赋值重载会把原资源释放,把新资源转移到被赋值的指针中。


#include<memory>
#include<iostream>
using namespace std;
int main()
{
	auto_ptr<int> ap(new int[10]);
	auto_ptr<int> ap1(ap);

	if (ap.get() == nullptr)
		cout << "权限转移:ap->ap1" << endl;

	auto_ptr<int> ap2;
	ap2 = ap1;
	if(ap1.get() == nullptr)
		cout << "权限转移:ap1->ap2" << endl;

	return 0;
}
权限转移:ap->ap1
权限转移:ap1->ap2

 


2.std::unique_ptr

        unique_ptr的实现原理:简单粗暴的防拷贝。

        强行将赋值重载和拷贝构造设置为 无法调用:具体可能是 直接加上 = delete ;或者是只声明不实现,并且放在私有。
        其余部分接口的使用与auto_ptr 基本一致。

 


3.std::shared_ptr

        shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。

引用计数原则: 

         1. shared_ptr在其内部,给每个资源都维护了着一份计数p_count,用来记录该份资源被几个指针维护。
        2. 在对象(指针)被销毁时(也就是析构函数调用时),就说明这个对象(指针)不维护该资源了,对象的引用计数减一。
        3. 如果引用计数减到0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
        4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。

         shared_ptr由于通过引用计数实现,其使用方法最接近普通指针,所以这里不再举例如何使用。我们仅仅需要对其几个常用接口熟悉即可。

 std::shared_ptr文档


对于以上的三种智能指针,其底层实现我们暂时不涉及,本篇只设计其思想与使用方法。 


完~

未经作者同意禁止转载 

标签:std,auto,C++,智能,初识,shared,ptr,指针
From: https://blog.csdn.net/2301_79465388/article/details/141530471

相关文章

  • 莫队算法C/C++实现
    目录简介 算法原理算法步骤C++实现应用场景莫队算法(Mo'sAlgorithm)是一种用于解决区间查询和更新问题的算法,由俄罗斯选手莫洛佐夫(MoMorozov)提出。它在算法竞赛和某些计算密集型任务中非常有用,尤其是在需要处理大量区间查询和更新操作时。莫队算法以其高效性和简洁性......
  • A*算法C/C++实现
    A*算法是一种在图形平面上,有多个节点的路径中,寻找一条从起始点(source)到目标点(goal)的最短遍历路径的算法。它属于启发式搜索算法,因为它使用启发式方法来计算图中的节点,从而减少实际计算的节点数量。A*(A星)算法是一种启发式搜索算法,用于在图中找到从起始点(source)到目标点(goal)的......
  • 【C++PCL】点云处理贪婪三角化曲面重建
    作者:迅卓科技简介:本人从事过多项点云项目,并且负责的项目均已得到好评!公众号:迅卓科技,一个可以让您可以学习点云的好地方重点:每个模块都有参数如何调试的讲解,即调试某个参数对结果的影响是什么,大家有问题可以评论哈,如果文章有错误的地方,欢迎来指出错误的地方。目录   ......
  • [C++ Error] f0202.cpp(13): E2268 Call to undefined function 'system'
    system('pause');解决方法,修改代码:system("pause");[C++Error]f0202.cpp(13):E2268Calltoundefinedfunction'system'错误解释:这个错误表明您在C++代码中尝试调用了一个未定义的函数system。system函数是C标准库中的函数,用于执行一个字符串中给出的命令。在C++中,......
  • C++暂停黑窗口 system( “pause “);
    在编写的c++程序中,如果是窗口,有时会一闪就消失了,如果不想让其消失,在程序结尾处添加:system("pause");注意:不要再return的语句之后加,那样就执行不到了。分析:system()是调用系统命令;pause暂停命令;这样在运行到此处时,会显示“Pressanykeytocontinue...”也就是“按任意键......
  • C++拾趣——转换编译器生成的类型名为代码中的类型名
    大纲代码测试代码地址在软件开发中,特别是在使用C++这类静态类型语言时,编译器在编译过程中会生成许多内部表示,包括类型信息。这些内部类型名通常用于编译器的内部处理,比如类型检查、优化和代码生成等。然而,在编写源代码或进行调试时,我们更习惯于使用人类可读和易于理......
  • 初识混沌工程(Chaos Engineering): k8s install chaosblade
    混沌工程文档:https://chaosblade.io/docs/helm:https://github.com/helm/helm/releaseschaosblade:https://github.com/chaosblade-io/chaosblade/releaseschaosblade-box:https://github.com/chaosblade-io/chaosblade-box/releasesmetrics-server:https://gith......
  • C++函数调用栈从何而来
    竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~个人主页:rainInSunny | 个人专栏:C++那些事儿、Qt那些事儿目录写在前面原理综述x86架构函数调用栈分析如何获取rbp寄存器的值总结写在前面  程序员对函数调用栈是再熟悉不过了,无论是使用IDE调试还是GDB等工具进行调试,都离......
  • C++函数调用栈从何而来
    竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~个人主页:rainInSunny | 个人专栏:C++那些事儿、Qt那些事儿文章目录写在前面原理综述x86架构函数调用栈分析如何获取rbp寄存器的值总结写在前面  程序员对函数调用栈是再熟悉不过了,无论是使用IDE调试还是GDB......
  • 【C++ 面试 - 内存管理】每日 3 题(一)
     ✍个人博客:Pandaconda-CSDN博客......