首页 > 其他分享 >智能指针

智能指针

时间:2024-04-18 15:15:28浏览次数:25  
标签:std p1 智能 shared unique ptr 指针

芝士wa
2024.4.8
参考视频链接


概述

C++的指针包括两种:

  • 原始指针
  • 智能指针:unique_ptr,shared_ptr,weak_ptr

智能指针是原始指针的封装,其优点是会自动分配内存,不用担心潜在的内存泄漏。

各种指针中,最常用的是裸指针,其次是unique_ptr和shared_ptr

weak_ptr是shared_ptr的一个补充,应用场景较少

智能指针只解决一部分问题,即独占/共享所有权指针的释放、传输


auto_ptr被C++抛弃的主要原因

  1. 复制或者赋值都会改变资源的所有权

     auto_ptr<string> p1(new string("a"));
     auto_ptr<string> p2(new string("b"));
     
     p1 = p2;
    

    当p2赋值给p1后,首先p1会将自己原先托管的指针释放掉,然后接受p2所托管的指针,p2指向NULL。

  2. 在STL容器中使用auto_ptr存在着重大风险,因为容器内的元素必须支持可复制和可赋值

  3. 不支持对象数组的内存管理

    auto_ptr<int[]> array(new int[5]);//不能这样定义


unique_ptr

  • 在任何时刻,只能有一个指针管理内存,两个unique_ptr不能指向同一个资源
  • 当指针超过作用域时,内存将自动释放
  • 该类型指针不可copy,只可以move
  • 在容器中保存指针是安全的

三种创建方式

  • 通过已有裸指针创建
  • 通过new来创建
  • 通过std::make_unique创建(推荐)

创建一个空的unique_ptr对象:

  std::unique_ptr<int> ptr;//空指针

使用原始指针创建,将一个new操作符返回的指针传递给unique_ptr的构造函数,

  std::unique_ptr<class> ptr(new class());
  std::unique_ptr<class> ptr = std::unique_ptr<class>(new class());
  //以上两句代码是等价的,第一句使用了直接初始化,第二句创建了一个临时对象,然后将该临时对象复制给ptr

不能通过赋值的方法创建对象,下面的这句是错误的

  std::unique_ptr<class> ptr = new class();//error

C++14引入了std::make_unique创建unique_ptr对象,可以使用std:::make_unique()函数创建

  std::unique_ptr<class> ptr = std::make_unique<class>();

推荐使用make_unique方法。

unique_ptr的操作

  • 使用get()函数获取管理对象的指针
   class *p1 = ptr.get();//get()会返回地址
  • 重置对象
    在unique_ptr对象上调用reset()函数将重置它,释放原始指针并置空
  ptr.reset();

检查unique_ptr对象是否为空

 // 方法1
    if(!ptr)
    	std::cout<<"ptr is empty"<<std::endl;
    // 方法2
    if(ptr == nullptr)
    	std::cout<<"ptr is empty"<<std::endl;

无法进行复制构造和赋值操作

 int main() 
  {
     // 创建一个unique_ptr实例
      unique_ptr<int> pInt(new int(5));
      unique_ptr<int> pInt2(pInt);    // 报错
      unique_ptr<int> pInt3 = pInt;   // 报错
  }
  1. 使用move函数移交所有权
   std::unique_ptr<class> p1 = std::make_unique<class>();
    std::unique_ptr<class> p2 = std::make_unique<class>();
    p2 = p1.move();//此时p1置空,p2获得p1原先指向对象的所有权。
  1. unique_ptr可以作为函数返回值

  2. 释放关联的原始指针
    在 unique_ptr 对象上调用 release()将释放其关联的原始指针的所有权,并返回原始指针。这里是释放所有权,并没有delete原始指针,reset()会delete原始指针。


shared_ptr

采用引用计数的办法,可以记录引用特定内存对象的智能指针数量,当复制或拷贝时,引用计数加1,当智能指针析构时,引用计数减1,如果计数为零,代表已经没有指针指向这块内存,那么我们就释放它。这就是shared_ptr采用的策略。

创建方法

  1. 默认构造函数
 std::shared_ptr<T> ptr;//空指针
  1. 使用裸指针进行构造
  std::shared_ptr<T> ptr(new T);
  1. 拷贝构造
   std::shared_ptr<T> ptr1;
   std::shared_ptr<T> ptr2(ptr1);//两个指针指向相同的资源,共同管理其生命周期
  1. 使用自定义删除器进行构造
 std::shared_ptr<T> ptr(new T, deleter);//删除器是一个函数或函数对象,用于在 std::shared_ptr 对象释放资源时执行自定义的清理操作。
  1. 使用自定义删除器和分配器进行构造
 std::shared_ptr<T> ptr(new T, deleter, allocator);//配器用于在 std::shared_ptr 对象需要重新分配内存时进行内存分配操作。
  1. 推荐使用make_shared方法
  std::shared_ptr<int> ptr = std::make_shared<int>(42);

通过 std::make_shared 创建的 std::shared_ptr 具有以下优点:

  • 内存分配是一次性完成的,同时包含对象和控制块,减少了内存开销。
  • 更安全,避免了裸指针的使用,因为 std::make_shared 会处理资源的释放。
  • 更高效,因为 std::make_shared 可以对内存进行更优化的管理。

shared_ptr操作

  1. 引用计数
    调用use_count函数可以获得当前托管指针的引用计数

  2. 管理动态数组

  std::shared_ptr<int[]> ptr(new int[5]);
  1. 主动释放对象
      shared_ptrr<int> up1(new int(10));
      up1 = nullptr ;	// int(10) 的引用计数减1,计数归零内存释放

  1. 重置
      p.reset() ; //将p重置为空指针,所管理对象引用计数减1
      p.reset(p1); //将p重置为p1(的值),p 管控的对象计数减1,p接管对p1指针的管控
      p.reset(p1,d); //将p重置为p1(的值),p 管控的对象计数减1并使用d作为删除器

  1. 交换
      std::swap(p1,p2); // 交换p1 和p2 管理的对象,原对象的引用计数不变
      p1.swap(p2);    // 交换p1 和p2 管理的对象,原对象的引用计数不变

weak_ptr

  1. weak_ptr指针通常不单独使用,只能和 shared_ptr 类型指针搭配使用。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象也还是会被释放。
  2. weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。

构造方法

  shared_ptr<class T> sp;
  weak_ptr wp;     //定义为空的弱指针
  weak_ptr wp2(sp);//使用共享指针构造
  wp2 = sp;        //允许共享指针赋值给弱指针

操作方法

  • 弱指针也可以获得引用计数,但不能改变引用计数
  wp.use_count();

  • 弱指针不支持*和->对指针的访问

  • 可以转换成共享指针lock()
    lock()函数:如果当前 weak_ptr 已经过期,则该函数会返回一个空的 shared_ptr 指针;反之,该函数返回一个和当前 weak_ptr 指向相同的 shared_ptr 指针。

  shared_ptr<class T> sp_T;
  sp_T = wp.lock();

  sp_T = nullptr;
  • 重置
    reset()函数:将当前 weak_ptr 指针置为空指针。

  • expired()

判断当前 weak_ptr 指针为否过期(指针为空,或者指向的堆内存已经被释放)

死锁问题

如果有两个shared_ptr相互引用,那么这两个shared_ptr指针的引用计数永远不会下降为0,资源永远不会释放。
举例:

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

class B;
class A
{
public:
    shared_ptr<B> pb_;
    ~A()
    {
        cout << "A delete\n";
    }
};
class B
{
public:
    shared_ptr<A> pa_;
    ~B()
    {
        cout << "B delete\n";
    }
};

void fun() {
    shared_ptr<B> pb(new B());
    cout << "pb.use_count " << pb.use_count() << endl;//1
    shared_ptr<A> pa(new A());
    cout << "pa.use_count " << pa.use_count() << endl;//1

    pb->pa_ = pa;
    cout << "pb.use_count " << pb.use_count() << endl;//1
    cout << "pa.use_count " << pa.use_count() << endl;//2
    pa->pb_ = pb;
    //由于share_ptr是共享资源,所以pb所指向的资源的引用计数也会加1
    cout << "pb.use_count " << pb.use_count() << endl;//2
    cout << "pa.use_count " << pa.use_count() << endl;//2
}//程序结束时,没有调用A和B的析构函数

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

为了解决死锁问题,采用weak_ptr,把A中的shared_ptr pb_ 改为weak_ptr pb_weak,传递时不会增加计数,最终能使资源正常释放。

标签:std,p1,智能,shared,unique,ptr,指针
From: https://www.cnblogs.com/cheese-wa/p/18121779

相关文章

  • 智能调度_AIRIOT智能车队管理解决方案
    客运、货运、汽车租赁、出租运营等行业对车辆管理、车队管理以及司乘人员的管理方式,逐渐向数字化和智能化转型。传统的依赖人工调度、记录和跟踪的管理模式已经难以满足业务发展需要,存在如下痛点:实时监控与定位功能弱:无法实时获取车辆的位置信息、行驶速度、方向、里程等动态数......
  • 05-智能调度-调度任务
    1.智能调度在神领物流项目中,采用智能调度的方式对车辆任务、快递员的取派件任务进行调度管理,这样更加有效的进行管理,降低企业运营成本。1.1为什么需要调度?可能你会这样的疑问,用户下单了,快递员上门取件,取件后送回网点,网点有车辆运走,再经过车辆的一系列的运输,最后进行派件,对方......
  • 06-智能调度-运输任务
    1.任务调度1.1分析通过前面的实现,已经将相同转运节点的写入到了Redis的队列中,谁来处理呢?这就需要调度任务进行处理了,基本的思路是:查询待分配任务的车辆→计算运力→分配运单→生成运输任务→生成司机作业单也就是说,调度是站在车辆角度推进的。1.2实现这里采......
  • NLP自然语言处理—主题模型LDA回归可视化案例:挖掘智能门锁电商评价数据
    全文链接:http://tecdat.cn/?p=2175早在1995年比尔·盖茨就在《未来之路》里说过:未来没有配套智能家居的房子,就是毛坯房。现在人们生活越来越便捷,人们也更加倾向于智能化家居,当你还在纠结“人工智能”安利值不值得吃,最近不少朋友家里又出现智能门锁,相比传统门锁来说,究竟能有多智能......
  • 生成性人工智能支持教师专业发展:对高阶思维和自我效能的影响
    (SupportingTeachers’ProfessionalDevelopmentWithGenerativeAI:TheEffectsonHigherOrderThinkingandSelf-Efficacy)一、摘要研究目的:生成式人工智能已经成为人类科学和技术领域主要学科发展史上一个值得注意的里程碑和重大进展。本研究旨在探讨生成式人工智能辅......
  • 迈向人工智能LLM的新征程:我的2023年转行之旅
    随着2023年的日历即将翻到最后一页,我迎来了人生中的一个重要转折点——转行进入人工智能LLM领域。这是一个充满挑战和机遇的新征程,我满怀期待地踏上了这片未知而又充满可能性的土地。大型语言模型(LLM)作为人工智能的重要分支,近年来取得了令人瞩目的进展。它们在自然语言处理、文本......
  • 免费在线OCR识别工具TextIn Tools,开启智能学习新时代
    传统的学习方式,笔记必须手写摘抄;带字照片只能插入文档;PDF转换要花钱买会员……而在线OCR识别工具tools.textin.com,既好用又免费,它不仅仅具有文字和表格识别工具,还包含PDF转文件等工具,能够做到一站式服务为用户解决所有问题。首先,它在我们学习场景中的应用可谓多种多样,废话不......
  • 视频质量AI智能分析诊断系统解决方案建设思路与设计
    一、建设背景随着安防视频覆盖日趋完善,视频在安全管理等方面发挥了不可替代的作用,但在使用过程中仍然存在视频掉线、视频人为遮挡、视频录像存储时长不足等问题,存在较大的安全隐患。1)视频在安全生产管理上作用日趋凸显,视频质量需长期保障受环境、老化、网络、供电、人为等多方......
  • vptr和vtbl(虚指针和虚函数表)
    vptr和vtbl(虚指针和虚函数表)c++代码的抽象类是->类当中只包含纯虚函数当一个类有虚函数,即便类当中没有成员变量.他的对象大小也会有一根指针大小->由操作系统决定指针多大虚函数子类的对象里面有父类的成分示例结构代码:#pragma#ifndef__VPTR_AND_VTBL__#define__V......
  • rust引用计数智能指针Rc<T>
    大部分情况下所有权是非常明确的:可以准确地知道哪个变量拥有某个值。然而,有些情况单个值可能会有多个所有者。例如,在图数据结构中,多个边可能指向相同的节点,而这个节点从概念上讲为所有指向它的边所拥有。节点在没有任何边指向它从而没有任何所有者之前,都不应该被清理掉。为了启用......