c++-智能指针

news2025/1/10 21:08:36

1、概念

堆内存的对象需要手动使用delete销毁,如果忘记使用delete销毁就会造成内存泄漏。

所以C++在ISO 98标注中引入了智能指针的概念,并在C++11 中趋于完善。

使用智能指针可以让堆内存对象具有栈内存对象的特性。原理时给需要自动回收的堆内存对象套上一层栈内存的模板类对象即可。

C++有四种智能指针:

  • auto_ptr (自动指针,已经废弃)(C++ISO 98)
  • unique_ptr (唯一指针)(C++ISO 11)
  • shared_ptr (共享指针)(C++ISO 11)
  • weak_ptr (协助指针)(C++ISO 11)

使用智能指针需要引入头文件#include<memory>

2、auto_ptr

#include <iostream>
#include <memory>
using namespace std;
class Test
{
private:
    string s;
public:
    Test(string s):s(s)
    {
        cout << s << "构造函数" << endl;
    }
    ~Test()
    {
        cout << s << "析构函数" << endl;
    }
    void show()
    {
        cout << s << "执行程序" << endl;
    }
};
int main()
{
    {
        Test *t1 = new Test("A");
        // 创建一个智能指针管理t1
        auto_ptr<Test> ap1(t1); // ap1 管理t1
        // 取出被管理的堆内存对象,并调用show成员函数
        ap1.get()->show(); 
        // 释放控制权
//        ap1.release();
        // 创建B堆对象,B将A顶掉,A对象销毁
        ap1.reset(new Test("B"));
        ap1.get()->show();

        // 释放控制权并且销毁资源对象
        ap1.reset();
        cout << "局部代码块执行结束" << endl;
    }
    return 0;
}

释放对象不会调用析构函数,只有销毁对象才会有

由于成员变量存在指针类型,因此拷贝构造函数与赋值运算符的使用会出现问题。与浅拷贝的问题不同的是,auto_ptr的复制语义会引起资源对象控制权转移的问题。

#include <iostream>
#include <memory>
using namespace std;
class Test
{
private:
    string s;
public:
    Test(string s):s(s)
    {
        cout << s << "构造函数" << endl;
    }
    ~Test()
    {
        cout << s << "析构函数" << endl;
    }
    void show()
    {
        cout << s << "执行程序" << endl;
    }
};

int main()
{
    {
        Test *t1 = new Test("A");
        // 创建一个智能指针管理t1
        auto_ptr<Test> ap1(t1); // ap1 管理t1
        auto_ptr<Test> ap2(ap1);    // 显式调用拷贝构造函数
        cout << ap1.get() << " " << ap2.get() << endl; // 0 0x1052780
        auto_ptr<Test> ap3 = ap2;   // 隐式调用构造函数
        // 0 0 0xe82780
        cout << ap1.get() << " " << ap2.get() << " " << ap3.get() << endl;
        auto_ptr<Test> ap4;
        ap4 = ap3;  // 赋值运算符
        // 0 0 0 0x922780
        cout << ap1.get() << " " << ap2.get() <<
                " " << ap3.get() << " " << ap4.get() << endl;

    }
    return 0;
}

3、unique_ptr

作为对auto_ptr的改进,unique_ptr对其他持有的资源对象具有唯一控制权,即不可以通过常规的复制语义转移或拷贝资源对象的控制权。

通过特殊的语法实现控制权的转移效果。

#include <iostream>
#include <memory>

using namespace std;

class Test
{
private:
    string s;
public:
    Test(string s):s(s)
    {
        cout << s << "构造函数" << endl;
    }
    ~Test()
    {
        cout << s << "析构函数" << endl;
    }

    void show()
    {
        cout << s << "执行程序" << endl;
    }
};

int main()
{
    {
        Test *t1 = new Test("A");
        // 创建一个智能指针管理t1
        unique_ptr<Test> up1(t1); // up1 管理t1
        unique_ptr<Test> up2(move(up1));    // 显式调用拷贝构造函数
        cout << up1.get() << " " << up2.get() << endl; // 0 0x1052780

        unique_ptr<Test> up3 = move(up2);   // 隐式调用构造函数
        // 0 0 0xe82780
        cout << up1.get() << " " << up2.get() << " " << up3.get() << endl;

        unique_ptr<Test> up4;
        up4 = move(up3);  // 赋值运算符
        // 0 0 0 0x922780
        cout << up1.get() << " " << up2.get() <<
                " " << up3.get() << " " << up4.get() << endl;

    }
    return 0;
}

4、shared_ptr

unique_ptr对资源具有独占性,多个shared_ptr对象可以共享资源。

shared_ptr有两种创建方式:

两种创建方式的区别在于后者是一步到位(创建资源对象+关系绑定),前者分为两步完成(先创建资源对象,再进行关系绑定)。

新方式的优点:

  • 安全性更好
  • 性能更好

新方式的缺点:

  • 资源释放效率低

每多一个shared_ptr对资源进行管理,引用计数将+1,每个指向该对象的shared_ptr对象销毁时,引用计数-1,最后一个shared_ptr对象销毁时,计数清零,资源对象销毁。

#include <iostream>
#include <memory>
using namespace std;
class Test
{
private:
    string s;
public:
    Test(string s):s(s)
    {
        cout << s << "构造函数" << endl;
    }
    ~Test()
    {
        cout << s << "析构函数" << endl;
    }
    void show()
    {
        cout << s << "执行程序" << endl;
    }
};
int main()
{
    shared_ptr<Test> sp3;
    {
        shared_ptr<Test> sp1 = make_shared<Test>("A");
        cout << "引用计数:" << sp1.use_count() << endl;

        shared_ptr<Test> sp2(sp1); // 拷贝构造函数
        cout << "引用计数:" << sp2.use_count() << endl;

        sp3 = sp2;
        cout << "引用计数:" << sp3.use_count() << endl;
    }
    cout << "引用计数:" << sp3.use_count() << endl;
    return 0;
}

5、weak_ptr

weak_ptr是一个不控制资源对象的智能指针,也不会影响资源的引用计数,其主要目的是协助shared_ptr工作。

通过weak_ptr的构造函数,参数传入一个持有资源对象的shared_ptr对象或者weak_ptr对象即可创建。

weak_ptr与资源对象呈现弱相关性,所以不支持get等函数直接操作资源对象。

建议weak_ptr调用lock函数之前,先检测引用计数是否大于0,或使用expried()函数检测是否可以转换为shared_ptr。

lock()函数,通过传入持有资源对象的对象创建新对象

#include <iostream>
#include <memory>
using namespace std;
class Test
{
private:
    string s;
public:
    Test(string s):s(s)
    {
        cout << s << "构造函数" << endl;
    }
    ~Test()
    {
        cout << s << "析构函数" << endl;
    }
    void show()
    {
        cout << s << "执行程序" << endl;
    }
};
int main()
{
    weak_ptr<Test> wp3;
    {
        shared_ptr<Test> sp1 = make_shared<Test>("A");
        weak_ptr<Test> wp1 = sp1;
        cout << sp1.use_count() << endl; // 1
        cout << wp1.use_count() << endl; // 1

        weak_ptr<Test> wp2(wp1); // 拷贝构造
        cout << wp2.use_count() << endl;

        shared_ptr<Test> sp2 = wp1.lock();
        cout << sp2.use_count() << endl; // 2

        wp3 = wp2;
        cout << wp3.use_count() << endl;
    }
    cout << wp3.use_count() << endl; // 0

    if(wp3.expired())
    {
        cout << "无法使用lock函数,因为没有可以管理的对象" << endl;
    }
    return 0;
}

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

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

相关文章

【本科生通信原理】【实验报告】【北京航空航天大学】实验一:通信原理初步

一、实验目的&#xff1a; 熟悉 MATLAB开发环境、掌握 MATLAB基本运算操作&#xff1b;熟悉和了解 MATLAB图形绘制基本指令&#xff1b;熟悉使用 MATLAB分析信号频谱的过程&#xff1b;掌握加性白高斯噪声信道模型 二、实验内容&#xff1a; 三、实验程序&#xff1a; 1、 f…

经历和经验的联系

2023年国内互联网大厂疯狂裁员&#xff0c;还出来了“防御性编程”&#xff0c;“开猿节流&#xff0c;降本增笑”等等词汇。阿里裁员后阿里云宕机多次&#xff0c;腾讯裁员和降级了领导层&#xff0c;这些领导回到大头兵岗位&#xff0c;不能融入一线干活&#xff0c;任务完成…

React基础应用及常用代码

目录 基础知识 babel.config.js js,html,css,Vue,react,angular,nodejs,webpack,less,ES6,commonjs等的关系 ECMAScript 6&#xff08;ES6&#xff09; let、const、var 的区别 Webpack、npm、node关系 props和state区别 通用框架类 ES 6 export React React.Fragm…

生信技能33 - gnomAD数据库hg19/hg38 VCF文件批量下载脚本

gnomAD数据库下载地址 gnomAD downloads gnomAD v2.1.1数据集包含来自125,748个外显子组和15,708个全基因组的数据,所有这些数据都映射到GRCh 37/hg 19和GRCh 38/hg 38 两个版本的参考序列。 gnomAD数据库hg19与hg39 VCF文件批量下载脚本 download.sh # 获取当前目录路径…

Spring IOC的四种手动注入方法

手动注入 1.Set方法注入-五种类型的注入1.1 业务对象JavaBean第一步&#xff1a;创建dao包下的UserDao类第二步&#xff1a;属性字段提供set⽅法第三步&#xff1a;配置⽂件的bean标签设置property标签第四步&#xff1a;测试 1.2 常用对象String&#xff08;日期类型&#xff…

【CMake】1. VSCode 开发环境安装与运行

CMake 示例工程代码 https://github.com/LABELNET/cmake-simple 插件 使用 VSCode 开发C项目&#xff0c;安装 CMake 插件 CMakeCMake ToolsCMake Language Support &#xff08;建议&#xff0c;语法提示) 1. 配置 CMake Language Support , Windows 配置 donet 环境 这…

用通俗易懂的方式讲解:OpenAI 新版 API 使用介绍,帮助大家快速解锁这些新功能

OpenAI 最近举办了首次开发者大会&#xff0c;大会上不仅发布了 GPTs 这样王炸级别的新功能&#xff0c;还发布了一些新模型&#xff0c;比如gpt-4-turbo等&#xff0c;模型的知识截止时间也提高到了 2023 年 4 月。 同时配合这些新模型&#xff0c;OpenAI 还开放了大家期盼已…

Anaconda + Pytorch 超详细安装教程

Anaconda Pytorch 超详细安装教程 安装 Anaconda 略,自行百度即可 安装 Pytorch 虚拟环境 第一步 选择 env第二步 创建第三步 填写环境名称和选择 python 版本号 第四步 打开 https://pytorch.org/ 选择 pytorch 版本&#xff0c;我这里选择的是 GPU 版本 即 CUDA 11.8,也…

Mysqld的关键优化参数

skip-name-resolve 现象 mysql连接很慢&#xff0c;登陆到服务器上查看服务器日志都是正常的&#xff0c;无可疑记录&#xff0c;登陆到mysql服务器上&#xff0c;查看下进程&#xff0c;发现有很多这样的连接&#xff1a; 218 | unauthenticated user | 192.168.10.6:44500 |…

vue简单实现滚动条

背景&#xff1a;产品提了一个需求在一个详情页&#xff0c;一个form表单元素太多了&#xff0c;需要滚动到最下面才能点击提交按钮&#xff0c;很不方便。他的方案是&#xff0c;加一个滚动条&#xff0c;这样可以直接拉到最下面。 优化&#xff1a;1、支持滚动条&#xff0c;…

宏基因组序列分析工具EukRep

文章&#xff1a;Genome-reconstruction for eukaryotes from complex natural microbial communities | bioRxiv 仓库&#xff1a;patrickwest/EukRep: Classification of Eukaryotic and Prokaryotic sequences from metagenomic datasets (github.com) 推荐使用conda进行安…

机械配件移动商城课程概述

项目介绍 开发准备 任务 开源库介绍 框架搭建 工具类

C++-异常处理

1、概念 异常时程序在执行期间产生的问题。C异常是指在程序运行时发生的特殊情况。比如string::at函数下标越界等。 异常提供了一种转移程序控制权的方式。 一旦程序出现异常没有经过处理&#xff0c;就会造成程序运行崩溃。 处理异常的方式有&#xff1a;抛出异常&#xff08;…

算法每日一题:队列中可以看到的人数 | 单调栈

大家好&#xff0c;我是星恒 今天是一道困难题&#xff0c;他的题解比较好理解&#xff0c;但是不好想出来&#xff0c;接下来就让我带大家来捋一捋这道题的思路&#xff0c;以及他有什么特征 题目&#xff1a;leetcode 1944有 n 个人排成一个队列&#xff0c;从左到右 编号为 …

【面试高频算法解析】算法练习6 广度优先搜索

前言 本专栏旨在通过分类学习算法&#xff0c;使您能够牢固掌握不同算法的理论要点。通过策略性地练习精选的经典题目&#xff0c;帮助您深度理解每种算法&#xff0c;避免出现刷了很多算法题&#xff0c;还是一知半解的状态 专栏导航 二分查找回溯&#xff08;Backtracking&…

使用Python给图片加水印(通过OpenCV和Pillow实现,内含完整代码链接)

from PIL import Image, ImageFont, ImageDraw, ImageEnhance, ImageChops import cv2 import math import numpy as npdef crop_image(im):"""裁剪图片边缘空白"""bg Image.new(mode"RGBA", sizeim.size)bbox ImageChops.differenc…

vite + vue3引入ant design vue 报错

npm install ant-design-vue --save下载插件并在main.ts 全局引入 报错 解决办法一&#xff1a; main.ts注释掉全局引入 模块按需引入 解决办法二 将package.json中的ant-design-vue的版本^4.0.0-rc.4改为 ^3.2.15版本 同时将将package-lock.json中的ant-design-vue的版本…

打造私域流量的知识付费小程序saas租户平台

当今信息爆炸的时代&#xff0c;知识管理已经成为了每个人必须面对的问题。然而&#xff0c;市面上的知识付费平台大多数都是通用的&#xff0c;无法满足个性化需求。 因此&#xff0c;明理信息科技提供了一款专属定制的适合个人的知识付费平台。核心产品能力如下&#xff1a;…

Huggy Lingo: 利用机器学习改进 Hugging Face Hub 上的语言元数据

太长不看版: Hub 上有不少数据集没有语言元数据&#xff0c;我们用机器学习来检测其语言&#xff0c;并使用 librarian-bots 自动向这些数据集提 PR 以添加其语言元数据。 Hugging Face Hub 已成为社区共享机器学习模型、数据集以及应用的存储库。随着 Hub 上的数据集越来越多&…

git打tag以及拉取tag

场景&#xff1a;某次git代码发布后定版记录&#xff0c;将发版所在的commit时候代码打上tag记录&#xff0c;方便后期切换到对应tag代码位置。 查看所有tag名 git tag// 1.1.0 // 1.0.0查看tag和描述 git tag -l -n//1.0.0 云监管一期项目完结 //1.1.0 …