独占指针 std::unique_ptr

2023-11-10

学习智能指针之前需要知道的:

  • 智能指针是原始指针的封装,在头文件<memory>中,优点就是自动分配内存,不用担心潜在的内存泄漏。
  • 不是所有的指针都可以封装成智能指针,很多时候原始指针更方便。
  • 各指针中,最常用的还是裸指针,其次就是unique_ptr 和 shared_ptr
  • weak_ptr 是 shared_ptr 的一个补充,使用较少
  • auto_ptr 被弃用

智能指针只解决 独占 / 共享 所有权指针的释放、传输,没有根本上解决 C++ 内存安全问题


unique_ptr 独占指针

性质:

  • 在任何给定的时刻,只能有一个指针管理内存
  • 当指针超出作用域时,内存将自动释放
  • 该类型指针不可以 Copy,只可以 Move

创建方式:

  • 通过已有裸指针创建
  • 通过 new 创建
  • 通过 std::make_unique 创建

获取地址:

  • 类方法 get() 获取地址

-> 与 * :

  • 通过 -> 调用成员函数
  • 通过 * 调用 dereferencing

智能指针的使用

测试代码: 

#include <iostream>
#include <memory>

class Stu {
    
    std::string m_name;

public:
    Stu() {
        this->m_name = "stuTemp";
        std::cout << "无参构造" << std::endl;
    }
    Stu(std::string name) :m_name(name) {
        std::cout << "有参构造" << std::endl;
    }
    ~Stu() {
        std::cout << "析构" << std::endl;
    }

    void printStuName() const {
        std::cout << this->m_name << std::endl;
    }
};


int main() {

    /* 创建智能指针3种方法 */
    // 1、原始指针创建
    Stu* s_p1 = new Stu("stu1");
    std::unique_ptr<Stu> u_s_p1{ s_p1 };
    u_s_p1->printStuName();

    // 2、new 
    std::unique_ptr<Stu> u_s_p2{ new Stu("stu2")};
    u_s_p2->printStuName();

    // 3、make_unique
    std::unique_ptr<Stu> u_s_p3 = std::make_unique<Stu>("stu3");
    u_s_p3->printStuName();


    //...
    //std::unique_ptr<int> u_i_p1 = std::make_unique<int>(10);
    //std::cout << "value:" << *u_i_p1 << std::endl;
    //std::cout << "address:" << u_i_p1 << std::endl;
    //std::cout << "address:" << u_i_p1.get() << std::endl;
    //std::cout << "address:" << u_s_p3.get() << std::endl;

    std::cout << "----------------" << std::endl;

    return 0;
}

运行结果:


unique_ptr 与 函数调用

传入值的方式:

  • 需要使用 std::move 来转移内存拥有权
  • 如果参数直接传入 std::make_unique 语句 自动转换为 move

传入引用的方式:

  • 如果设置参数为 const 则不能修改指向,eg:不能 reset()
  • reset() 方法为智能指针清空方法

函数返回值的方式:

  • 指向一个 local object
  • 可以用作链式函数

测试代码:

#include <iostream>
#include <memory>

class Stu {
    
    std::string m_name;

public:
    Stu() {
        this->m_name = "stuTemp";
        std::cout << "无参构造" << std::endl;
    }
    Stu(std::string name) :m_name(name) {
        std::cout << "有参构造" << std::endl;
    }
    ~Stu() {
        std::cout << "析构" << std::endl;
    }

    void printStuName() const {
        std::cout << this->m_name << std::endl;
    }

    void setStuName(std::string name) {
        this->m_name = name;
    }
};


void doWithStuPassValue(std::unique_ptr<Stu> s) {
    s->printStuName();
}

void doWithStuPassRef(const std::unique_ptr<Stu>& s) {
    s->setStuName("JJ");
    s->printStuName();
    //s.reset(); // 清空
}

std::unique_ptr<Stu> getUniquePtr() {
    std::unique_ptr<Stu> u_s_p1 = std::make_unique<Stu>("Local");
    std::cout << "address:" << u_s_p1.get() << std::endl;
    return u_s_p1;
}

int main() {
    // 1、passing by value
    std::unique_ptr<Stu> u_s_p1 = std::make_unique<Stu>("NN");
    doWithStuPassValue(std::move(u_s_p1)); // 使用 move 转移所有权
    //u_s_p1->printStuName(); // 使用已移动的对象

    doWithStuPassValue(std::make_unique<Stu>("MM")); // 默认转换成 move 形式

    // 2、passing by reference
    std::unique_ptr<Stu> u_s_p2 = std::make_unique<Stu>("KK");
    doWithStuPassRef(u_s_p2);
    //u_s_p2->printStuName();
    //std::cout << u_s_p2 << std::endl; // 0
    //std::cout << u_s_p2.get() << std::endl; // 0
    //u_s_p2->printStuName();
    
    // 3、Return by value
    getUniquePtr()->printStuName();

    return 0;
}

运行结果:

在函数参数方面,传入参数时,传入的是智能指针就需要使用 move 来转移内存拥有权,如果是直接传入 make_unique 语句,则会默认进行 move。

-

推荐使用的方法是将函数参数修改为 const 加 引用。 就可以直接传入智能指针。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

独占指针 std::unique_ptr 的相关文章

  • C++ 中本地类中的静态成员变量?

    我知道我们不能宣布static本地类中的成员变量 但其原因尚不清楚 那么请问有人可以解释一下吗 另外 为什么我们不能访问非static函数内部定义的变量 内部已经定义了局部类 直接在局部类成员函数中 在下面给出的代码中 int main i
  • 互斥体实现可以互换(独立于线程实现)

    所有互斥体实现最终都会调用相同的基本系统 硬件调用吗 这意味着它们可以互换吗 具体来说 如果我使用 gnu parallel算法 使用openmp 并且我想让他们称之为线程安全的类我可以使用boost mutex用于锁定 或者我必须编写自己
  • 单元测试一起运行时失败,单独运行时通过

    所以我的单元测试遇到了一些问题 我不能只是将它们复制并粘贴到这里 但我会尽力而为 问题似乎是 如果我一项一项地运行测试 一切都会按预期进行 但如果我告诉它一起运行测试 则 1 5 将通过 TestMethod public void Obj
  • 如何访问另一个窗体上的ListView控件

    当单击与 ListView 所在表单不同的表单中的按钮时 我试图填充 ListView 我在 Form1 中创建了一个方法以在 Form2 中使用 并将参数传递给 Form1 中的方法 然后填充 ListView 当我调试时 我得到了传递的
  • C++中的类查找结构体数组

    我正在尝试创建一个结构数组 它将输入字符串链接到类 如下所示 struct string command CommandPath cPath cPathLookup set an alarm AlarmCommandPath send an
  • 使用 C 语言使用 strftime() 获取缩写时区

    我看过this https stackoverflow com questions 34408909 how to get abbreviated timezone and this https stackoverflow com ques
  • 如何在 Linq 中获得左外连接?

    我的数据库中有两个表 如下所示 顾客 C ID city 1 Dhaka 2 New york 3 London 个人信息 P ID C ID Field value 1 1 First Name Nasir 2 1 Last Name U
  • 如何将整数转换为 void 指针?

    在 C 中使用线程时 我面临警告 警告 从不同大小的整数转换为指针 代码如下 include
  • 批量更新 SQL Server C#

    我有一个 270k 行的数据库 带有主键mid和一个名为value 我有一个包含中值和值的文本文件 现在我想更新表格 以便将每个值分配给正确的中间值 我当前的方法是从 C 读取文本文件 并为我读取的每一行更新表中的一行 必须有更快的方法来做
  • Visual Studio 中的测试单独成功,但一组失败

    当我在 Visual Studio 中单独运行测试时 它们都顺利通过 然而 当我同时运行所有这些时 有些通过 有些失败 我尝试在每个测试方法之间暂停 1 秒 但没有成功 有任何想法吗 在此先感谢您的帮助 你们可能有一些共享数据 检查正在使用
  • 上下文敏感与歧义

    我对上下文敏感性和歧义如何相互影响感到困惑 我认为正确的是 歧义 歧义语法会导致使用左推导或右推导构建多个解析树 所有可能的语法都是二义性的语言是二义性语言 例如 C 是一种不明确的语言 因为 x y 总是可以表示两个不同的事物 如下所述
  • 如何使用 Mongodb C# 驱动程序连接多个集合

    我需要将 3 个集合与多个集合合并在一起 lookup我在 C 驱动程序中尝试过 它允许我 lookup用户采集但无法执行秒 lookup用于设置集合 有人可以帮忙吗 db Transactions aggregate lookup fro
  • 将 log4net 与 Autofac 结合使用

    我正在尝试将 log4net 与 Autofac 一起使用 我粘贴了这段代码http autofac readthedocs org en latest examples log4net html http autofac readthed
  • 如何编写一个同时需要请求和响应Dtos的ServiceStack插件

    我需要提供本地化数据服务 所有本地化的响应 Dto 都共享相同的属性 IE 我定义了一个接口 ILocalizedDto 来标记那些 Dto 在请求端 有一个ILocalizedRequest对于需要本地化的请求 Using IPlugin
  • HttpWebRequest 在第二次调用时超时

    为什么以下代码在第二次 及后续 运行时超时 代码挂在 using Stream objStream request GetResponse GetResponseStream 然后引发 WebException 表示请求已超时 我已经尝试过
  • gcc 的配置选项如何确定默认枚举大小(短或非短)?

    我尝试了一些 gcc 编译器来查看默认枚举大小是否很短 至少一个字节 强制使用 fshort enums 或无短 至少 4 个字节 强制使用 fno short enums user host echo Static assert 4 si
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • 有没有办法强制显示工具提示?

    我有一个验证字段的方法 如果无法验证 该字段将被清除并标记为红色 我还希望在框上方弹出一个工具提示 并向用户显示该值无效的消息 有没有办法做到这一点 并且可以控制工具提示显示的时间 我怎样才能让它自己弹出而不是鼠标悬停时弹出 If the
  • 线程和 fork()。我该如何处理呢? [复制]

    这个问题在这里已经有答案了 可能的重复 多线程程序中的fork https stackoverflow com questions 1235516 fork in multi threaded program 如果我有一个使用 fork 的
  • memset 未填充数组

    u32 iterations 5 u32 ecx u32 malloc sizeof u32 iterations memset ecx 0xBAADF00D sizeof u32 iterations printf 8X n ecx 0

随机推荐

  • 人事管理系统 数据流图_大学毕业设计-宾馆管理系统

    目录 第一章 绪论 1 1 1概述 1 第二章 宾馆管理系统系统分析 1 2 1可行性分析 1 2 2 需求分析 2 第三章 系统概要设计 2 3 1 功能需求 2 3 2 主要功能 3 3 3 系统开发目的 3 3 4 运行环境 3 3
  • 异步日志的实现

    异步日志的实现 异步管理类 异步工厂类 登录校验 登录 异步管理类 采用单例模式的静态饥饿加载 利用空间换时间 提高效率 使用异步延迟任务线程池 通过其内直接创建饥一个static对象 形成饥饿加载 以达到记录日志时的单例模式 import
  • Android-Studio-常用配置和快捷键

    原文链接http www open open com lib view open1466732917214 html articleHeader1 http www jianshu com p bc8f6bfe12c6 以下直接在 Sett
  • VS版本、GCC版本与C++版本的对应关系

    做嵌入式开发经常遇到一些编译器和C 版本不匹配的问题 现整理如下 目前C语言的标准有 C89 ANSI C C90 C95 C99 ISO C C11 C1x 目前C 语言的标准有 C 98 C 03 对98小幅修改 C 11 全面进化 C
  • C语言与C++,C#究竟是什么关系?

    简单来说 C 就像是C语言的亲弟弟 而C 就是他们二者的远房亲戚 其实它更像是Java的表兄弟 小编c 学习群825414254获取c 一整套系统性的学习资料还有数十套pdf这三门语言都是十分优秀的编程语言 也都有很高的运行效率 这三种编程
  • Gradle是个啥东东?

    如何通俗地理解 Gradle 我以前一直用 Eclipse with ADT 来开发Android 项目 而且对它的基础的原理掌握不深 直接上手开发的 没有去考虑太多的东西 现在手头上有一个新的项目要使用到Android Studio 我早
  • SQL编程:外键约束

    外键 foreign key 一个表中的foreign key指向另一个表中的unique key 唯一约束的键 对于两个具有关联关系的表而言 相关联字段中主键所在的表就是主表 外键所在的表就是从表 子表 外键约束 foreign key约
  • SpringCloud gateway+zookeeper实现网关路由

    准备工作 需要两个项目去实现路由 demo1为springboot项目用于接入网关 测试网关连通性 gateway为网关路由项目 网关搭建 1 电脑安装好zookeeper 并且正常运行服务 Zookeeper官网 2 创建一个spring
  • python3 100示例学习

    http www runoob com python python 100 examples html
  • CSS属性之渐变属性(gradient)

    渐变分为线性渐变和径向渐变 所谓渐变就是几种颜色之间的平稳过渡 线性渐变 线性渐变 linear gradient 实现线性渐变 你至少需要定义两种颜色的结点 这两种结点就是你想平稳过渡的颜色 即 其中一种颜色结点为起点 另一种颜色结点为结
  • 论文阅读—基于目标偏置的双向APF-RRT*算法的无人机轨迹规划

    基于目标偏置的双向APF RRT 算法的无人机轨迹规划 算法 APF选择最好的父节点 双向搜索树 主要提升策略 实验分析 J Fan X Chen and X Liang UAV trajectory planning based on b
  • 40核至强服务器性能如何,Intel 10nm 14核心至强曝光:同频性能暴涨54%

    日前我们曾经从GeekBench测试数据库里见到一颗疑似Intel 10nm Ice Lake SP服务器平台的6核心型号 外媒称对比现有14nm产品 多线程性能提升多达118 颇为不可思议 但真实性也有待检验 现在 SiSoftware数
  • 期刊分区常识

    作为一个科研工作者 了解期刊论文的一些基本常识是大有裨益的 这对于我们深入了解所从事领域的研究 和论文的写作与发表等都会有很大的帮助 比如对于期刊分区的问题 从事科研的人都听过 但是也许你并没有深入了解其概念和意义 尤其对于刚刚步入科研领域
  • 用docker 创建centos7 ,无法使用systemctl解决方法

    docker run privileged it d name centos odoo centos centos7 9 2009 usr sbin init 1 privileged it d 一定要加 2 name 后面是容器名称和使用
  • 一句话征服了美国人,这位饱受争议的数学博士竟从未上过学?

    全世界只有3 14 的人关注了 青少年数学之旅 前两天 有位不愿意透露姓名的模友问了超模君一个问题 虽然这个问题超模君已经解答过无数遍了 但看到模友如此虔诚的态度 超模君决定今天再给模友们讲一个犹太小伙用数学征服美国军官的故事 偌大维也纳
  • qt的visible hide 等布局隐藏函数

    https blog csdn net dbzhang800 article details 6300021
  • xpath手册

    XPath手册 源于ZVON AAA AAA CCC AAA DDD BBB BBB DDD BBB AAA CCC DDD BBB AAA BBB 1 AAA BBB last id BBB id BBB name BBB BBB not
  • 手机驱动工程师门,准备转行了吗

    前80后从事手机研发的年轻人目前已经人到中年后了 时间过得真的很快 从2004左右开始红火的山寨手机 已经耗去了你们青春 你们中的不少人也从中过得不错的收益 但随着iPhone的出现 智能手机视乎在一瞬间就冒了出来 大佬Nokia都没有缓过
  • 交换机与路由器技术-05-路由器工作原理

    目录 一 路由器的工作原理 1 1 回顾交换机的工作原理 1 2 回顾路由器相关知识 1 3 网络层IP数据包格式 二 路由器工作原理 2 1 路由 2 2 路由器工作模式 2 3 路由表 2 4 静态路由 2 5 动态路由 2 6 分层次
  • 独占指针 std::unique_ptr

    学习智能指针之前需要知道的 智能指针是原始指针的封装 在头文件