C++ 智能指针(一) auto_ptr

news2024/11/14 14:09:17

文章目录

  • 前言 - 什么是智能指针?
  • std::auto_ptr
    • auto_ptr的使用
      • 常用成员方法:
        • 1. get()方法
        • 2. release()方法
        • 3. reset()方法
        • 4. operator=()
        • 5. operator*() & operator->()
    • auto_ptr的局限性

前言 - 什么是智能指针?

在全文开始之前,我们先来看一段代码:

class Object{
public:
    Object(){cout<<"Create Object"<<endl;}
    ~Object(){cout<<"Free Resources"<<endl;}
    void run(){
        throw -1;
    }
};
int main(){
    Object* pObj = new Object();
    pObj->run();
    delete pObj;
}

执行这段代码我们只会得到"Create Object"的输出,这表明析构函数没有被调用。有时候我们会忘记delete,有些时候,就像上面的代码一样,中途发生异常也会导致对象无法正常地释放资源,从而导致内存泄漏。

对此,C++之父Bjarne Stroustrup提出了 RAII(Resource Acquisition Is Initialization) 机制,翻译过来就是“资源获取就是初始化”。RAII要求由对象的构造函数完成资源的分配,同时由析构函数,完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。而 C++智能指针 正是RAII的实践。

C++ STL提供了四种智能指针:std::auto_ptrstd::unique_ptrstd::shared_ptrstd::weak_ptr。它们包含在<memory>之中。在本篇,我们会讲std::auto_ptr

std::auto_ptr

auto_ptr是C++98提出的一种智能指针,它在C++11中就已经被弃用,在C++17中就完全去除了它。因为auto_ptr有很多局限性。所以,在我们实际的开发中不建议使用,但是它还是有必要讲的。在本文中,我们会先讲它的用法,再讲它的局限。

auto_ptr的使用

创建auto_ptr的方法如下:(其余的智能指针创建方法也都于此相同,后面就不多赘述了)

auto_ptr<Object> pObj(new Object());

Notice:
注意不能使用如下的方式创建,因为其构造函数阻止了隐式转换:

//The following code is incorrect
auto_ptr<Object> pObj = new Object();

常用成员方法:

其中 get()operator*()operator->()为观察器,reset()release()为修改器。

1. get()方法

要获取其托管对象的地址可以使用get()方法:

auto_ptr<Object> pObj(new Object);
Object* pObj1 = pObj.get();
delete pObj1;

2. release()方法

如果我们此时想要取消托管,可以使用release()方法,这个函数会取消智能指针的所有权,并返回托管对象的地址:

auto_ptr<Object> pObj(new Object);
Object* pObj1 = pObj.release();
delete pObj1;

3. reset()方法

要替换管理对象,可以使用reset()方法。如果传入的为空,则释放托管对象资源并置空,如果传入另一指针,先释放前一指针,再托管后面的:

class Object{
public:
    Object(){cout<<"Create Object"<<endl;}
    ~Object(){cout<<"Free Resources"<<endl;}
    void run(){
        throw -1;
    }
public:
    int num=100;
};
int main(){
    auto_ptr<Object> pObj(new Object());
    cout<<"Addr: "<<pObj.get()<<endl;
    pObj.reset(new Object());
    cout<<"Addr: "<<pObj.get()<<endl;
}

输出如下:

Create Object
Addr: 0x26622b0
Create Object
Free Resources
Addr: 0x26622f0
Free Resources

4. operator=()

转移auto_ptr所有权,下面的代码将pObj1的所有权转交给了pObj2:

auto_ptr<Object> pObj1(new Object());
auto_ptr<Object> pObj2 = pObj1;

Notice:
注意这里不要与前面创建不能使用“=”搞混了,这里是重载赋值,而前面是隐式转换。

5. operator*() & operator->()

如果要访问托管的对象可以使用*,访问托管对象的成员可以使用->

auto_ptr<Object> pObj(new Object);
cout<<pObj->num;

auto_ptr的局限性

首先,auto_ptr意义不明确,使用浅拷贝方式时,两个对象拥有同一块资源,这样就会调用两次析构函数,有可能导致程序崩溃:

class Object{
public:
    Object(){cout<<"Create Object"<<endl;}
    ~Object(){cout<<"Free Resources"<<endl;}
    void run(){
        throw -1;
    }
};
int main(){
    Object* pObj = new Object();

    auto_ptr<Object> pObj1(pObj);
    auto_ptr<Object> pObj2(pObj);
}

结果如下:

Create Object
Free Resources
Free Resources

并且auto_ptr没有引用计数,转移所有权以后,如果在后面访问了前面对象的成员,程序就会Crash:

class Object{
public:
    Object(){cout<<"Create Object"<<endl;}
    ~Object(){cout<<"Free Resources"<<endl;}
    void run(){
        throw -1;
    }
public:
    int num=100;
};
int main(){
    Object* pObj = new Object;
    auto_ptr<Object> pObj1(pObj);
    auto_ptr<Object> pObj2(pObj1);
    cout<<pObj1->num;
}

可以看到pObj2已经拥有所有权,再访问pObj1->num就会报错
在这里插入图片描述

此外auto_ptr对象并不能作为STL容器的元素,因为C++的STL容器对于容器元素类型的要求是有值语义,即可以赋值和复制,auto_ptr在赋值和复制时都进行了特殊操作;也不能声明为数组,因为auto_ptr无法识别数组,其内部析构时是用的delete而非delete [],它只会析构一次,导致内存泄漏:

int main(){
    Object* pObj = new Object[3];
    auto_ptr<Object> pObj1(pObj);
}

输出结果为:

Create Object
Create Object
Create Object
Free Resources

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/182577.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis事务的概述、设计与实现

1 Redis事务概述事务提供了一种“将多个命令打包&#xff0c; 然后一次性、按顺序地执行”的机制&#xff0c; 并且事务在执行的期间不会主动中断 —— 服务器在执行完事务中的所有命令之后&#xff0c; 才会继续处理其他客户端的其他命令。以下是一个事务的例子&#xff0c; 它…

mysql-事务以及锁原理讲解(二)

1、前言 众所周知&#xff0c;事务和锁是mysql中非常重要功能&#xff0c;同时也是面试的重点和难点。本文会详细介绍事务和锁的相关概念及其实现原理&#xff0c;相信大家看完之后&#xff0c;一定会对事务和锁有更加深入的理解。 2、什么是事务 在维基百科中&#xff0c;对事…

7 处理多维特征的输入

文章目录课程前提知识问题引入模型改进修改神经层的增加学习能力与超参数课本代码课程来源: 链接课程文本来源借鉴&#xff1a; 链接以及&#xff08;强烈推荐&#xff09;Birandaの课程前提知识 BCELoss - Binary CrossEntropyLoss BCELoss 是CrossEntropyLoss的一个特例&am…

JavaEE day7 初识JavaScript2

函数小结 1.可以赋值给变量(其实就是被变量所指向) 2.装入容器中作为元素存在 3.在函数调用的过程中&#xff0c;函数类型作为实参 4.函数作为另一个函数的返回值 可以直接return一个函数 5.和java不同&#xff0c;JS中允许在一个函数中定义另一个函数&#xff0c;也就是嵌…

介绍一个令强迫症讨厌的小红点组件

前言 在 App 的运营中,活跃度是一个重要的指标,日活/月活……为了提高活跃度,就发明了小红点,然后让强迫症用户“没法活”。 小红点虽然很讨厌,但是为了 KPI,程序员也不得不屈从运营同学的逼迫(讨好),得想办法实现。这一篇,来介绍一个徽标(Badge)组件,能够快速搞…

解决OpenEuler系统 Minimal BASH-like line editing is supported

2023年开工解决的第一个问题~呃&#xff0c;起因是这样的&#xff0c;由于业务需要&#xff0c;修改内核参数后重新打包内核&#xff0c;然后安装内核rpm包后&#xff0c;强制关机&#xff0c;结果就出现如上界面。网上搜索后绝大部分是因为安装了双系统后找不到grub系统引导文…

ELK_Elasticsearch基础介绍

目录 一、搜索是什么&#xff1f; 二、数据库做搜索的弊端 三、全文检索、倒排索引和Lucene 四、什么是Elasticsearch 1、Elasticsearch的功能 2、Elasticsearch的使用场景 3、Elasticsearch的特点 五、elasticsearch核心概念 一、搜索是什么&#xff1f; 概念&#x…

vue2与vue3面试题之区别

目录vue2与vue3面试题之区别01&#xff1a;数据双向绑定&#xff08; proxy 替代 defineProperty&#xff09;02&#xff1a;生命周期函数的更换03&#xff1a;vue3的新特性04&#xff1a;缓存组件与更新组件05&#xff1a;ref和reactive的区别06&#xff1a;watch和watchEffec…

测试篇(五):什么是自动化测试、自动化测试分类、selenium工具、第一个自动化测试程序

目录一、什么是自动化测试二、自动化测试分类2.1 单元测试2.2 UI自动化测试三、selenium工具3.1 selenium的介绍3.2 环境部署3.3 selenium的常用方法四、第一个自动化测试用例一、什么是自动化测试 在日常生活中我们会见到&#xff0c;自动化的水龙头、无人驾驶汽车、自动化的…

Mysql,使用FIND_IN_SET()函数处理多表关联问题.

这里有 user表、teacher表&#xff0c;其中 teacher.user_ids 字段中的值是 user.id 值以英文半角逗号拼接而来。现在&#xff0c; 我们需要在查询 teacher 表数据时&#xff0c;将 user.name 的值也查询出来。使用以下的SQL语句&#xff0c;即可实现需求。SELECTGROUP_CONCAT(…

系统编程中的进程的概念No.1

引言&#xff1a; 北京时间2023/1/28&#xff0c;本小编04年1月9日出生&#xff0c;今天第一次理解到进程的概念&#xff0c;所以我们接下来就学习一下什么是进程以及和进程相关的一些知识。首先我们想要了解进程以及其相关的知识&#xff0c;我们要先理解一下其它方面的知识&…

【2】Linux基础命令

学习笔记目录 初识Linux--入门Linux基础命令--会用Linux权限管控--懂权限Linux实用操作--熟练实战软件部署--深入掌握脚本&自动化--用的更强项目实战--学到经验云平台技术--紧跟潮流 Linux的目录结构 Linux的目录结构是一个树形结构&#xff0c;没有盘符这个概念&#x…

常用算法分类

按照使用场景分类排序算法&#xff0c;如冒泡排序&#xff0c;快速排序等&#xff0c;用于将一组数据按照特定规则排序。搜索算法&#xff0c;如二分查找算法&#xff0c;深度优先搜索算法等&#xff0c;用于在一组数据中查找特定元素。图论算法&#xff0c;如最短路径算法&…

Claude的2022年终总结——关于2022和Claude的四个问题

文章目录前言1. 我算是合格的开发者了吗2. 我算是正式的游戏人了吗3. 我算是成熟的社会人了吗4. 我算是什么样的写作者呢最后前言 2022年的这个时候&#xff0c;我也是在准备着年终总结&#xff0c;只不过应公司要求&#xff0c;准备述职晋升&#xff0c;是抱着升职加薪&#…

行为型模式 - 命令模式Command

模式的定义与特点 命令模式&#xff08;Command Pattern&#xff09;&#xff0c;是将一个请求封装成一个对象&#xff0c;从而使您可以用不同的请求对客户进行参数化。命令模式是把发出命令的责任和执行命令的责任分割开&#xff0c;委派给不同的对象。命令模式允许请求的一方…

设计一个消息队列的思考点

导图所以主要考虑的点是&#xff1a;P1.1. MQ 要有基础的消息管理能力&#xff08;CRUD&#xff09;P1.2. MQ 要有产消日志P2. MQ将消息存储成功才能响应成功P3.1 MQ将消息存储 分片存储P3.2 扩容的实现思路(如何在扩容的时候更方便高效)P4.1 数据要有副本&#xff08;分片副本…

【27】C语言 | 指针进阶

目录 一、指针概念 二、字符指针 三、指针数组 四、数组指针 五、数组参数、指针参数 六、函数指针 七、函数指针数组 八、回调函数 一、指针概念 1.指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。2.指针的大小是固定的4/8个字节(32位平…

Java ccflow 代码

草稿规则目录概述需求&#xff1a;设计思路实现思路分析1.URL管理参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,challenge Survive. happ…

盖子的c++小课堂——第十四讲:指针

前言 作者&#xff1a;大家好鸭&#xff0c;想必大家看到标题都有感到有一丝奇怪吧&#xff0c;其实&#xff0c;今天主要讲一些运算符 粉丝&#xff1a;啊……嗯嗯嗯 作者&#xff1a;那开始吧~~ 内存地址运算符& 粉丝&#xff1a;讲这个干嘛&#xff0c;我都会了~~ …

Jmeter场景组合测试——多个线程组的设计方案

我们绝大多数同学在使用jmeter进行性能测试时都会在一个线程组中完成测试工作&#xff0c;今天我来重点讲解一下jmeter多个线程组在测试中的应用&#xff0c;这也是关于jmeter性能测试面试过程中的进阶问题&#xff0c;希望能够帮到大家来解决工作中不同的测试需求。线程组中的…