C++的智能指针学习笔记初

作者: goto2091

C++ primer plus 16.2节介绍了auto_ptr,该模板类在C++11中已弃用,目前已被shared_ptr代替。
auto_ptr又叫做智能指针,用于管理动态内存分配的用法。 为什么要有auto_ptr?

首先看一个例子,

void remodel(string &str){
  string *ps = new string(str);
  ...
  str = ps;
  return;
}

此例子有什么缺陷呢?

函数结束的时候没有释放内存,这导致了内存的泄露,指针ps会被释放,但是其指向的内存并没有被释放。一般来说,解决new导致的内存泄露的方法是在return之前使用delete.

但凡是涉及到"别忘了"的操作,都不是最佳的操作,因为一定会有开发者忘记,或者在不经意间删除或者注释掉了这些代码。

就算是没有忘记,也会因为一些别的操作导致内存无法释放,例如以下的代码:

void remodel(string &str)
{
  string *ps = new string(str);
  ...
  if(xxx){
    throw exception();
  }
  str = *ps;
  delete ps;
  return;
}

在delete执行之前,如果执行过程中产生了异常并抛出,则后续的指令都不会执行,这仍将导致内存泄露。 如何解决

首先,们知道,C++创建一个对象有两种方式,new和直接声明。new一个对象将在堆中动态分配内存来创建一个对象,而直接声明将会在栈内存中创建对象。
(所谓的堆,是指程序内部除了栈和静态存储区之外的"自由空间(free store)“,堆内存用于在程序运行时分配对象。)

前者的生命周期是全局的,后者则受到作用域限制,也就是说对于前者产生的对象,如果不去主动释放它,则该对象所占据的内存会一直存在,如果没有指针可以指向它,则会导致内存泄露。

而直接声明的对象,在一个类对象过期的时候,析构函数会在一个对象过期的时候自动执行从而将该对象释放。

不妨这样思考,如果指针能被封装为一个对象,则这个包含指针的对象过期的时候调用其析构函数,将该指针指向的对象delete,不就能够把它指向的内存也释放了吗?

于是auto_ptr便诞生了,auto_ptr是一个模板类,这样便可以创建指向任何类型的智能指针。 auto_ptr的设计和使用

template<class T>class auto_ptr{
  public:
  explicit auto_ptr(T* p = 0) throw();
};

throw()意味着构造函数不引发异常,因此请求T类型的auto_ptr将获得一个指向T类型的auto_ptr.

这样便定义好了一个智能指针,其实非常简单,就是在构造的时候将普通的指针放入了auto_ptr模板类中

使用的时候

auto_ptr<double> ap(new double);//在构造函数中填入new出来的对象
*ap = 23.3;//ap对象的地址其实就是new出来的double对象的地址,所以可以用指针取值的方式赋值。

所以,改造文章开头的remodel函数:

void remodel(string &str){
  auto_ptr<string> ps(new string(str));
  ...
  if(xxx) throw exception();
  str=*ps;
  return;
}

这里,便不再需要使用delete了。 shared_ptr和unique_ptr C++11摒弃了auto_ptr,主要是由于auto_ptr无法进行指针的传递。auto_ptr必须显式地初始化,即auto_ptr<string> ps(new string("sdf")),

为了多个指针指向一个new出的对象,C++11提出了shared_ptr,
shared_ptr中增加了引用计数,有N个指向一个同一个内存区域的shared_ptr时,它们共同维护一个引用计数器。
shared_ptr的大概实现如下:

template<typename T> class shared_ptr{

private:
  T* _ptr;//指向的对象
  int *_count;//引用计数器
public:
  ...
  shared_ptr():_ptr((T*)0),_count(0)
  ~shared_ptr(){
    if(_ptr && --*count==0){
      delete _ptr;
      delete _count;
    }
  }
};

当智能指针的析构函数启用时,只有引用计数为0的时候,才会进行析构。

原文创作:goto2091

原文链接:https://www.cnblogs.com/goto2091/p/13804187.html

更多推荐

更多
  • AWS自动化机器学习-十一、MLSDLC 的持续集成、部署和训练 技术要求,编纂持续集成阶段,管理持续部署阶段,管理持续训练,延伸,构建集成工件,构建测试工件,构建生产工件,自动化持续集成流程,回顾构建阶段,回顾测试阶段,审查部署和维护阶段,回顾应用用户体验,创建新的鲍鱼调查数据,回顾持续训练流程,清
    Apache CN

  • AWS自动化机器学习-六、使用 AWS 步骤函数自动化机器学习过程 技术要求,介绍 AWS 步骤功能,使用 Step 函数 Data Science SDK for CI/CD,建立 CI/CD 渠道资源,创建状态机,解决状态机的复杂性,更新开发环境,创建管道工件库,构建管道应用构件,部署 CI/CD
    Apache CN

  • AWS自动化机器学习-第三部分:优化以源代码为中心的自动化机器学习方法 本节将向您介绍整体 CI/CD 流程的局限性,以及如何将 ML 从业者的角色进一步整合到管道构建流程中。本节还将介绍这种角色集成如何简化自动化过程,并通过向您介绍 AWS Step 函数向您展示一种优化的方法。本节包括以下章节:
    Apache CN

  • AWS自动化机器学习-一、AWS 上的自动化机器学习入门 技术要求,洗钱流程概述,洗钱过程的复杂性,端到端 ML 流程示例,AWS 如何使 ML 开发和部署过程更容易自动化,介绍 ACME 渔业物流,ML 的情况,从数据中获得洞察力,建立正确的模型,训练模型,评估训练好的模型,探索可能的后续步
    Apache CN

  • AWS自动化机器学习-二、使用 SageMaker 自动驾驶器自动化机器学习模型开发 技术要求,介绍 AWS AI 和 ML 前景,SageMaker 自动驾驶器概述,利用 SageMaker 自动驾驶器克服自动化挑战,使用 SageMaker SDK 自动化 ML 实验,SageMaker Studio 入门,准备实验
    Apache CN

  • AWS自动化机器学习-四、机器学习的持续集成和持续交(CI/CD) 四、机器学习的持续集成和持续交CI/CD技术要求,介绍 CI/CD 方法,通过 CI/CD 实现 ML 自动化,在 AWS 上创建 CI/CD 管道,介绍 CI/CD 的 CI 部分,介绍 CI/CD 的 CD 部分,结束循环,采取以部
    Apache CN

  • AWS自动化机器学习-九、使用 Amazon Managed Workflows 为 Apache AirFlow 构建 ML 工作流 技术要求,开发以数据为中心的工作流程,创建合成鲍鱼调查数据,执行以数据为中心的工作流程,构建和单元测试数据 ETL 工件,构建气流 DAG,清理, 在前面的年龄计算器示例中,我们了解了如何通过 ML 从业者和开发人员团队之间的跨职能
    Apache CN

  • AWS自动化机器学习-七、使用 AWS 步骤函数构建 ML 工作流 技术要求,构建状态机工作流,执行集成测试,监控管道进度,设置服务权限,创建 ML 工作流程, 在本章中,我们将从第六章中的 [处继续,使用 AWS 步骤函数自动化机器学习过程。您将从那一章中回忆起,我们正在努力实现的主要目标是简化
    Apache CN

  • AWS自动化机器学习-八、使用 Apache Airflow 实现机器学习过程的自动化 技术要求,介绍阿帕奇气流,介绍亚马逊 MWAA,利用气流处理鲍鱼数据集,配置 MWAA 系统的先决条件,配置 MWAA 环境, 当建立一个 ML 模型时,有一个所有 ML 从业者都知道的基本原则;也就是说,最大似然模型只有在数据被训练时
    Apache CN

  • AWS自动化机器学习-五、自动化 ML 模型的持续部署 技术要求,部署 CI/CD 管道,构建 ML 模型工件,执行自动化 ML 模型部署,整理管道结构,创建 CDK 应用,部署管道应用,查看建模文件,审查申请文件,查看模型服务文件,查看容器构建文件,提交 ML 工件,清理, 在 [第 4
    Apache CN

  • 近期文章

    更多
    文章目录

      推荐作者

      更多