C++重新认知:智能指针

0/# 一、为什么要有智能指针
内存泄露是我们开发大型项目时最为头疼的问题,当我们将对象建立在堆上时,因为需要我们自己手动释放,因此避免不了忘记删除,或者删除时没有考虑清楚情况的问题,从而造成悬挂指针或者是野指针的问题。

二、智能指针是什么

简单理解的话,智能指针采用RAII机制。即虽然智能指针虽然是以指针的方式运作,但是实际上是一个对象,在自己生命周期结束后,会自动释放掉,这样的话就不用让开发人员时刻把心思放在释放对象这个问题上了,也降低了内存泄漏的概率。

在C++中,智能指针一共定义了4种:
auto_ptr、unique_ptr、shared_ptr 和 weak_ptr。 其中,auto_ptr在C++11种已经摒弃掉,在C++17中已经废除不可用。

三、智能指针

1、unique_ptr

在这里插入图片描述
指针p在运行完test()函数后会直接释放掉。
在这里插入图片描述
需要注意的是,unique_ptr并没有负责复制的构造函数,因此不支持拷贝和赋值操作。原因是unique_ptr会独享p1的所有权,如果p2和p3失去p1的所有权时(即p1释放掉)会delete p1两次,p1释放一次,p2释放会再次delete p1一次。
在这里插入图片描述
虽然不能够拷贝和赋值操作,但是可以将p1的所有权转移给p2管理,使用std::move函数即可。

unique最常见的使用场景,就是替代原始指针,为动态申请的资源提供异常安全保证。

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

class Test
{
   
public:
	void add();
};
void Test::add()
{
   
	;
}

int main()
{
   
	//情况一
	Test* t = new Test();
	t->add();
	delete t;
	//情况二
	unique_ptr<Test> t(new Test);
	t->add();
	delete t;
}

在这个场景中,如果情况一中 t 执行add()函数,执行过程中出现异常,导致无法执行后面无法释放掉对象。
而情况二中,即使 t 执行add()函数出现异常,无法继续后面delete t 代码时,但对象 t 生命周期结束后,智能指针会自动调用析构函数,释放掉对象。

2、shared_ptr

大部分提到的智能指针很大概率上指的是shared_ptr,它采用的机制是引用计数,即实现对一块内存的多个引用,在最后一个引用被释放时,指向的内存才释放。shared_ptr可以进行赋值和拷贝操作。
shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。
在这里插入图片描述
获取原始指针:在这里插入图片描述

注意事项:

  • 不能将一个原始指针初始化多个shared_ptr对象(因为会多次删除相同指针)
    在这里插入图片描述
  • 循环引用问题
#include<iostream>
#include<vector>
using namespace std;
struct Father
{
   
    shared_ptr<Son> son_;
};

struct Son
{
   
    shared_ptr<Father> father_;
};

int main()
{
   
     father = make_shared<Father>();
    auto son = make_shared<Son>();

    father->son_ = son;
    son->father_ = father;
	return 0;
}

该部分代码会有内存泄漏问题。原因是
1.main 函数退出之前,Father 和 Son 对象的引用计数都是 2。
2.son 指针销毁,这时 Son 对象的引用计数是 1。
3.father 指针销毁,这时 Father 对象的引用计数是 1。
4.由于 Father 对象和 Son 对象的引用计数都是 1,这两个对象都不会被销毁,从而发生内存泄露。

为避免循环引用导致的内存泄露,就需要使用 weak_ptr。weak_ptr 并不拥有其指向的对象,也就是说,让 weak_ptr 指向 shared_ptr 所指向对象,对象的引用计数并不会增加。
使用 weak_ptr 就能解决前面提到的循环引用的问题,方法很简单,只要让 Son 或者 Father 包含的 shared_ptr 改成 weak_ptr 就可以了。

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



struct Father
{
   
    shared_ptr<Son> son_;
};

struct Son
{
   
    weak_ptr<Father> father_;
};

int main()
{
   
    shared_ptr<Father> father = make_shared<Father>();
    shared_ptr<Son> son = make_shared<Son>();

    father->son_ = son;
    son->father_ = father;

    return 0;
}

相关推荐

  1. C++ 智能指针

    2024-02-17 19:46:01       51 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-17 19:46:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-17 19:46:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-02-17 19:46:01       82 阅读
  4. Python语言-面向对象

    2024-02-17 19:46:01       91 阅读

热门阅读

  1. 初识tensorflow程序设计模式

    2024-02-17 19:46:01       61 阅读
  2. Mongodb 文本检索

    2024-02-17 19:46:01       56 阅读
  3. FFmpeg编译安装外部库包括NVIDIA

    2024-02-17 19:46:01       62 阅读
  4. C++ 最多参加的场次。

    2024-02-17 19:46:01       54 阅读
  5. vue3 axios二次封装

    2024-02-17 19:46:01       64 阅读
  6. 安装GeoServer,配置CORS

    2024-02-17 19:46:01       50 阅读
  7. 面试计算机网络框架八股文十问十答第六期

    2024-02-17 19:46:01       57 阅读
  8. 国产计算机的种类和应用

    2024-02-17 19:46:01       48 阅读