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

智能指针详解

时间:2024-03-23 21:03:30浏览次数:20  
标签:std int 智能 详解 shared unique ptr 指针

文章目录


前言

智能指针本质上来讲是一个存储指向堆内存指针的类,目的就是帮助我们管理内存,一旦使用了智能指针就就尽量使用new产生的指针,因为智能指针只维护同类型指针的引用计数,混用很容易造成内存重复释放的问题


unique_ptr

std::unique_ptr是一种独占所有权的智能指针,它确保指向的对象只有一个所有者,并负责在其生命周期结束时自动释放对象,一块内存只能由一个unique_ptr进行管理,如果有其它的unique想要管理,就只能用move进行资源转移,它的内部计数不能超过1

使用场景:适用于管理单个所有者的对象,通常用于替代原始指针和new/delete操作。

使用方法:

  • 初始化
#include <memory>

int main() {
    std::unique_ptr<int> ptr(new int(42));
    // 使用ptr
    *ptr = 10;
    // ptr的生命周期结束时,会自动释放动态分配的内存
    return 0;
}

unique_ptr不允许复制,只能用move来移动所有权,如:

unique_ptr<int> ptr1 = move(ptr);
  • 数组
std::unique_ptr<int[]> arr(new int[size]); // 使用智能指针管理动态数组

shared_ptr

std::shared_ptr是一种共享所有权的智能指针,它允许多个std::shared_ptr指向同一个内存,通过引用计数来管理对象的生命周期,每多一个指针指向这个对象,它内部的引用计数就会加1,析构一个就减一,当引用计数为0的时候就调用它的析构函数释放这块内存

1.使用场景:适用于多个所有者的场景,允许对象被多个地方共享并且在最后一个所有者释放对象时销毁

2.使用方法:

  • 初始化
#include <memory>

int main() {
	//std::shared_ptr<int> ptr1 = new int(42);//错误,不允许用原始指针进行赋值
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);//最高效的一种初始化方法
    std::shared_ptr<int> ptr2 = ptr1; // 多个shared_ptr指向同一对象
    std::shared_ptr<int> ptr3(new int(1));//利用构造函数初始化
    // 使用ptr1和ptr2
    *ptr1 = 10;
    // 当最后一个shared_ptr被销毁时,对象会被释放
    return 0;
}
  • 管理动态数组
#include <memory>

int main() {
    int size = 10;
    std::unique_ptr<int[]> arr(new int[size]); // 使用智能指针管理动态数组

    // 对数组进行操作
    for (int i = 0; i < size; ++i) {
        arr[i] = i;
    }

    // 不需要手动释放内存,当 unique_ptr 被销毁时,动态数组内存会自动释放
    return 0;
}

3.使用注意事项:

  • 不要用一个原始指针初始化多个shared_ptr
int* ptr = new int;
shared_ptr<int> p1(ptr);
shared_ptr<int> p2(ptr);//错误,应该用p1初始化p2
  • 避免循环引用
#include <memory>

class B; // 前向声明类 B

class A {
public:
    std::shared_ptr<B> b_ptr; // A 持有对 B 的 shared_ptr
};

class B {
public:
    std::shared_ptr<A> a_ptr; // B 持有对 A 的 shared_ptr
};

int main() {
    std::shared_ptr<A> a(new A());
    std::shared_ptr<B> b(new B());

    // 循环引用
    a->b_ptr = b;
    b->a_ptr = a;

    return 0;
}

循环引用导致a和b的引用计数为2,由于释放一个 shared_ptr 时,如果其引用计数不为 1(即存在其他指针也指向同一块内存),则仅减少引用计数,而不会立即销毁管理的对象,因此离开作用域后引用计数减为1,内存泄漏,解决办法是把a和b的任意成员变量改为weak_ptr,如:

std::weak_ptr<A> a_ptr; // B 持有对 A 的 shared_ptr

为什么引用计数开始的时候无法减为0,而用了weak_ptr就能解决问题了,这是因为weak_ptr不会增加引用计数,我画一个图来说明一下
在这里插入图片描述

weak_ptr

std::weak_ptr是一种弱引用智能指针,它允许观察std::shared_ptr指向的对象,但不会增加引用计数,也不会阻止对象的销毁。

使用场景:通常用于解决std::shared_ptr循环引用导致的内存泄漏问题,或者在需要观察对象但不需要拥有所有权的情况下使用。

使用方法:

  • 用use_count获取当前观测的资源数
shared_ptr<int> sp(new int(10));
weak_ptr<int> wp(sp);
cout<<wp.use_count()<<endl;
  • 用expired判断所观测的资源是否已经释放
 std::shared_ptr<A> a_ptr; // B 持有对 A 的 shared_ptr
 weak_ptr<int> wp = sp;
 if(wp.expired()){
 	cout<<"释放过了已经"<<end;
}
  • 用lock获取所监视的shared_ptr
#include <memory>

int main() {
    std::shared_ptr<int> ptr = std::make_shared<int>(42);
    std::weak_ptr<int> weakPtr = ptr;
    // 使用weakPtr
    if (auto sharedPtr = weakPtr.lock()) {
        // 如果对象未被释放,则获取shared_ptr并使用
        *sharedPtr = 10;
    } else {
        // 对象已经被释放
    }
    return 0;
}

标签:std,int,智能,详解,shared,unique,ptr,指针
From: https://blog.csdn.net/m0_56049283/article/details/136972463

相关文章

  • JavaScript原型、原型对象、原型链系列详解(一)
    (一)、JavaScript原型原型JavaScript是一门面向对象的编程语言,其中原型(prototype)是一个重要的概念,它提供了一种创建对象的方式,使对象可以共享属性和方法。在JavaScript中,每个对象都有一个原型,可以从原型中继承属性和方法。原型的定义JavaScript的原型是一个对象,它......
  • 《数据结构与算法分析》作业一(详解版)
    1.什么是数据结构?有关数据结构的讨论涉及哪三个方面?答:(1)数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成.(2)逻辑结构、存储结构以及运算结构。2.什么是算法?算法的特性有哪些?根据这些特性,解释算法与程序的区别?答:(1)算法是一组明......
  • ☆【前后缀】【双指针】Leetcode 42. 接雨水
    【前后缀】【双指针】Leetcode42.接雨水解法1前后缀分解解法2双指针---------------......
  • 基于物联网的智能家居监测与控制系统(附源码+全套资料)
        本设计是基于物联网的OneNET云平台和TCP/IP网络通信设计的具有低成本高效率的智能家居控制系统。该系统通过手机APP与终端服务器设备相结合的方式进行搭建。手机APP采用C++语言通过QT开发,终端服务器设备采用ARM-Cortex_A9开发板作为服务器,M0开发板模拟温湿度数据的......
  • 机器学习:智能时代的核心引擎
    目录一、什么是机器学习二、监督学习三、无监督学习四、半监督学习五、强化学习一、什么是机器学习机器学习是人工智能的一个分支,它主要基于计算机科学,旨在使计算机系统能够自动地从经验和数据中进行学习并改进,而无需进行明确的编程。机器学习算法通过构建模型来处......
  • 模拟堆(详解+例题)
    一、定义维护一个数据集合,堆是一个完全二叉树。那么什么是二叉树呢?如图:二、关于小根堆实现性质:每个根节点都小于等于左右两边,所以树根为最小值。 2.1、堆存储(用一维数组来存) 记住规则:x(根)的左儿子=x*2;          x(根)的右儿子=x......
  • 分布式详解
    文章目录概述分布式开发优点和缺点分布式存在的作用分布式和集群的区别集群的特点BASE理论BASE理论的三要素CAP理论二段式满足cap理论的哪两个理论分析下分布式强一致性、弱一致性、最终一致性衡量分布式系统的指标分布式下down机的处理⽅案分布式系统设计paxos和raft......
  • C语言字符函数和字符串函数及内存函数详解(干货小知识:常用函数的模拟实现)
    文章目录1.字符函数1.1字符分类函数1.2字符转换函数2.字符串函数2.1strlen函数2.1.1strlen函数的使用:2.1.2strlen函数的模拟实现2.2strcpy函数2.2.1strcpy函数的使用2.2.2strcpy函数的模拟实现2.3strcat函数2.3.1strcat函数的使用2.3.2strcat函数的模拟实......
  • Redis基础命令集详解
    目录1.Redis基础命令2.Redis的经典案例2.1缓存2.2计数器2.3发布订阅Redis是一个开源、内存存储的数据结构服务器,它支持多种数据结构,如字符串、哈希表、列表、集合、有序集合等。在Redis中,使用一些基础的命令来操作这些数据结构。1.Redis基础命令下面是一些常用的R......
  • STM32之HAL开发——启动文件详解【精华版】
    启动文件介绍启动文件是使用机器认识的汇编语言,由汇编编写,是系统上电复位后第一个执行的程序,经过一些必要的配置,最终能够调用main函数,使得用户程序能够在MCU上正常运行起来的必备文件。无论是是何种MCU,从简单的51,MSP430,到ARM9,ARM11,A7都必须有启动文件,因为对于嵌入式......