首页 > 编程语言 >【C++】智能指针

【C++】智能指针

时间:2024-09-08 16:23:05浏览次数:5  
标签:std C++ 智能 shared unique ptr 指针

目录

1. 智能指针简介

2. std::unique_ptr

2.1. 特点

2.2. 使用示例

3. std::shared_ptr

3.1. 特点

3.2. 使用示例

4. std::weak_ptr

4.1. 特点

4.2. 使用示例

5. 使用智能指针的注意事项

5.1. 选择合适的智能指针类型

5.2. 避免循环引用

5.3. 谨慎使用自定义删除器

5.4. 注意智能指针的性能开销

5.5. 避免与裸指针混合使用

5.6. 合理使用移动语义

5.7. 注意智能指针的生命周期

5.8. 优先使用std::make_unique和std::make_shared

5.9. 避免重复释放

5.10. 理解和使用std::weak_ptr


1. 智能指针简介

C++智能指针是C++标准库中提供的一种自动管理动态分配内存的模板类。它们通过封装裸指针(即直接使用newdelete分配的指针)来自动管理内存的生命周期,从而减少了内存泄漏和野指针的风险。下面我将对C++中常见的几种智能指针(std::unique_ptrstd::shared_ptrstd::weak_ptr)进行详细解析。

2. std::unique_ptr

std::unique_ptr是一种独占所有权的智能指针,它保证了在同一时间内只有一个unique_ptr可以指向一个给定的对象。当unique_ptr被销毁时(例如,离开作用域),它所指向的对象也会被自动删除。std::unique_ptr不允许复制构造或复制赋值,但支持移动语义,允许通过移动构造和移动赋值来转移所有权。

2.1. 特点

  • 独占所有权:不能复制,但可以通过移动语义转移所有权。
  • 自定义删除器:可以指定一个自定义的删除函数或lambda表达式来替代默认的delete操作。
  • 数组支持:std::unique_ptr<T[]>专门用于管理动态分配的数组,其析构函数会调用delete[]来释放内存。

2.2. 使用示例

#include <memory>  
  
int main() {  
    std::unique_ptr<int> ptr1(new int(10)); // 创建unique_ptr  
    // std::unique_ptr<int> ptr2 = ptr1; // 错误,不能复制  
    std::unique_ptr<int> ptr3 = std::move(ptr1); // 通过移动语义转移所有权  
  
    // 此时ptr1变为空指针,ptr3指向原对象  
    return 0;  
}

3. std::shared_ptr

std::shared_ptr实现了共享所有权的智能指针,允许多个shared_ptr实例指向同一个对象。每个shared_ptr都有一个关联的计数器(通常隐藏在内部的控制块中),用于跟踪有多少个shared_ptr指向该对象。当最后一个指向该对象的shared_ptr被销毁时,对象才会被删除。std::shared_ptr支持复制构造和复制赋值,这允许所有权在多个shared_ptr之间共享。

3.1. 特点

  • 共享所有权:支持复制和赋值,所有权在多个shared_ptr之间共享。
  • 自定义删除器:同unique_ptr,可以指定自定义删除函数。
  • 循环引用问题:需要小心处理,可能会导致内存泄漏。

3.2. 使用示例

#include <memory>  
  
int main() {  
    std::shared_ptr<int> ptr1(new int(10));  
    std::shared_ptr<int> ptr2 = ptr1; // 复制,共享所有权  
  
    // 当ptr1和ptr2都销毁时,对象才会被删除  
    return 0;  
}

4. std::weak_ptr

std::weak_ptr是一种不拥有所指向对象的智能指针,它用于解决std::shared_ptr之间可能形成的循环引用问题。weak_ptr可以与shared_ptr互操作,但它不增加对象的共享所有权计数。但它不增加对象的共享所有权计数。当你想在不需要拥有对象的情况下观察对象时,std::weak_ptr非常有用。它允许你获取一个指向对象的std::shared_ptr(如果对象仍然存在),但如果不存在,则返回一个空的shared_ptr

4.1. 特点

  • 不拥有对象:不增加对象的共享所有权计数。
  • 避免循环引用:与shared_ptr配合使用,打破循环引用。
  • 转换为shared_ptr:可以通过lock()方法尝试获取一个指向对象的shared_ptr(如果对象仍然存在)。

4.2. 使用示例

#include <memory>  
#include <iostream>  
  
class A;  
class B;  
  
class A {  
public:  
    std::shared_ptr<B> bPtr;  
    ~A() { std::cout << "A destroyed\n"; }  
};  
  
class B {  
public:  
    std::weak_ptr<A> aPtr;  
    ~B() { std::cout << "B destroyed\n"; }  
};  
  
int main() {  
    std::shared_ptr<A> a = std::make_shared<A>();  
    std::shared_ptr<B> b = std::make_shared<B>();  
    a->bPtr = b;  
    b->aPtr = a;  
  
    // a和b都销毁时,由于使用了weak_ptr,没有循环引用问题  
    return 0;  
}

在这个例子中,AB类通过shared_ptrweak_ptr相互引用,但没有形成循环引用,因为B类中使用的是weak_ptr来引用A。因此,当abshared_ptr被销毁时,它们指向的对象也会被正确删除,不会造成内存泄漏。 

5. 使用智能指针的注意事项

使用C++智能指针时,需要注意以下几个方面以确保程序的正确性和效率。

5.1. 选择合适的智能指针类型

  • std::unique_ptr:适用于独占所有权的场景,确保同一时间内只有一个智能指针指向对象。它不支持复制构造和赋值操作,但支持移动语义。
  • std::shared_ptr:适用于共享所有权的场景,允许多个智能指针指向同一个对象。它通过引用计数来管理对象的生命周期,当最后一个shared_ptr被销毁时,对象也会被自动删除。
  • std::weak_ptr:不拥有对象的所有权,通常与std::shared_ptr配合使用,用于解决循环引用问题。它不会增加引用计数,但可以通过lock()方法尝试获取一个指向对象的shared_ptr(如果对象仍然存在)。

5.2. 避免循环引用

当使用std::shared_ptr时,需要特别注意避免循环引用,即两个或多个对象相互持有对方的shared_ptr,导致它们的引用计数无法归零,从而无法释放内存。为了避免循环引用,可以使用std::weak_ptr来替代其中一个shared_ptr

5.3. 谨慎使用自定义删除器

虽然智能指针允许指定自定义删除器,但应谨慎使用。自定义删除器可能会引入额外的复杂性和错误风险。在大多数情况下,使用默认的delete操作就足够了。

5.4. 注意智能指针的性能开销

智能指针相比裸指针具有额外的性能开销,因为它们需要维护额外的信息(如引用计数)。在性能敏感的场景中,应评估使用智能指针的必要性,并考虑可能的优化措施。

5.5. 避免与裸指针混合使用

尽量避免将智能指针与裸指针(即直接使用newdelete)混合使用,因为这可能会导致资源的重复释放或内存泄漏。如果确实需要使用裸指针访问智能指针所管理的对象,应确保在智能指针的生命周期内进行访问,并避免在智能指针销毁后继续使用裸指针。

5.6. 合理使用移动语义

对于std::unique_ptr,可以利用其移动语义来转移所有权,从而避免不必要的复制和性能开销。

5.7. 注意智能指针的生命周期

智能指针的生命周期应与它所管理的对象的生命周期相匹配。如果智能指针的生命周期过短,可能会导致对象被提前删除;如果过长,则可能会浪费内存资源。

5.8. 优先使用std::make_uniquestd::make_shared

在C++14及更高版本中,推荐使用std::make_uniquestd::make_shared来创建智能指针。这些函数能够更高效地分配内存,并减少代码量。

5.9. 避免重复释放

确保不要对同一个智能指针多次调用reset()release()delete(对于unique_ptr通过get()获取的裸指针),这可能会导致未定义行为,如双重释放。

5.10. 理解和使用std::weak_ptr

当需要观察std::shared_ptr管理的对象但不拥有它时,可以使用std::weak_ptr。它不会增加引用计数,因此不会阻止对象的销毁。但是,在访问对象之前,应使用lock()方法尝试获取一个std::shared_ptr,以确保对象仍然存在。

智能指针是C++中管理动态内存的强大工具,它们能够显著减少内存泄漏和程序崩溃的风险。然而,像任何强大的工具一样,它们也需要谨慎使用。

标签:std,C++,智能,shared,unique,ptr,指针
From: https://blog.csdn.net/weixin_37800531/article/details/142028398

相关文章

  • Linux 下 C/C++ 程序编译的过程
    目录一、GCC工具链二、编译过程1、预处理2、编译3、汇编4、链接本文将介绍如何将C/C++语言编写的程序转换成为处理器能够执行的二进制代码的过程,包括四个步骤:预处理(Preprocessing)编译(Compilation)汇编(Assembly)链接(Linking)。在此之前,首先来看一下GCC工具链。......
  • 基于大语言模型智能体的自主机器学习
    文章介绍了MLR-Copilot框架,这是一种利用大型语言模型(LLMs)来自动化机器学习研究中创意生成、实验设计和实施过程的方法。该框架分为三个阶段:首先通过阅读现有研究文献,使用LLM驱动的IdeaAgent来生成研究假设和实验计划;其次,ExperimentAgent将这些计划转换为可执行的代码,并检索原型代码......
  • C++11/14/17/20 新特性反汇编分析1
    区间for迭代类似于java中的foreach看个例子:数组的区间for迭代我们从第一行开始看,首先把数组a的地址放到eax中,再把eax的值放到[ebp-28h]中,也就是[ebp-28h]存储了元素的首地址,同理[ebp-34h]也存了a的首地址(这里猜测可能是多个变......
  • 家电制造集团智能制造数字化转型实施路径与举措:智能产品、智能生产、智能物流、智慧管
    随着科技的飞速发展,智能制造已成为家电制造业转型升级的重要方向。为了提升产品竞争力、优化生产流程、增强供应链协同效率并实现精细化管理,家电制造集团需全面推进智能制造数字化转型。本文将从智能产品设计、智能生产优化、智能物流管理、智慧管理体系、数据驱动决策、组织文......
  • 文心智能体“城市印象之走读北京”开发分享
       城市印象之走读北京(baidu.com)    这个智能体为笔者“城市印象”系列当中的作品之一,基于北京丰富的文化旅游资源,侧重于在历史文化方面进行多角度、个性化的城市走读,名为“城市印象之走读北京”。   通过开场白提示,从色彩、季节、器物等角度为使用者......
  • 基于django+vue智能新闻推荐系统【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,新闻信息呈现出爆炸式增长态势,用户面对海量新闻数据往往感到无所适从,难以快速准确地获取自己感兴趣的内容。传统......
  • c++IOS优化【原创】
    这一期,我们来讲IOS优化,上一期讲了GCC的优化,这次给大家带来的是IOS优化,代码如下。ios::sync_stdio(0),cin.tie(),cout.tie();ios::sync_with_stdio(0):默认情况下,C++的标准输入输出流(cin/cout)会与C语言的标准输入输出流(scanf/printf)同步。这可能会导致一些性能开销。当使用......
  • FlexibleBI智能制造的未来:通过自主可控的国产化三坐标CMM尺寸公差质量管理系统推动工
    在全球制造业的快速发展中,精准的尺寸测量与控制成为了确保产品质量和生产效率的关键因素。传统的尺寸测量和数据分析工具,例如Excel等手动方式,已无法满足现代工业对实时性、精准性和自动化的高要求。我们的智能制造解决方案通过人工智能赋能的预测分析,为企业提供了一个强大且......
  • FlexibleBI基于人工智能的工业软件,赋能制造业的智能化与高效生产
    在当今制造业,智能化和高效生产已成为企业保持竞争力的关键要素。我们的系统通过人工智能赋能,提供预测和质量控制功能,为企业提供强大的尺寸质量管理工具。这一系统专为尺寸公差管理、3D尺寸分析、质量控制及公差分析而设计,能够满足汽车制造业的高精度需求。FlexibleBI自主可控......
  • 状压DP(c++)
    好久都没来水博客了,现在闲的来写一篇刚学的状压DP思想状压DP要把一个集合中的所有元素一一分别拿出来讨论,需要用到二进制保存集合状态例如110001010二进制,0代表没有,1代表有这个元素876543210他的位置所有状压dp差不多就一个思想逐步将集合中的点包含进来首先引入一道题......