当前位置: 首页 > news >正文

独占指针 std::unique_ptr

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

  • 智能指针是原始指针的封装,在头文件<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 加 引用。 就可以直接传入智能指针。

相关文章:

  • 斐波那契的几种思路,你都会吗
  • 关于新冠的几点总结
  • 开源项目推荐 | 中科院自动化所历时9年打造的类脑认知智能引擎“智脉”正式开源部署至OpenI启智社区
  • Servlet基础教程 (保姆级教学)
  • vue经历从2.0到3.0更新
  • 安装mysqlclient失败解决办法
  • 华为OD机试真题 Java 实现【单词接龙】
  • Spring boot 日志直接推送到elasticsearch上
  • 网络部署运维实验(pat 端口映射含命令)
  • 软件测试期末复习(二)试题及答案
  • 智能家居创意DIY之智能灯泡
  • Linux——磁盘在网络中共享
  • 【Git】一文带你入门Git分布式版本控制系统(创建合并分支、解决冲突)
  • Spring Boot骚操作-多数据源Service层封装
  • 信贷--------
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • 【翻译】babel对TC39装饰器草案的实现
  • HashMap剖析之内部结构
  • input的行数自动增减
  • JavaScript 基本功--面试宝典
  • Joomla 2.x, 3.x useful code cheatsheet
  • Laravel Telescope:优雅的应用调试工具
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • node.js
  • PHP 小技巧
  • supervisor 永不挂掉的进程 安装以及使用
  • 不发不行!Netty集成文字图片聊天室外加TCP/IP软硬件通信
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 二维平面内的碰撞检测【一】
  • 今年的LC3大会没了?
  • 面试遇到的一些题
  • 前端存储 - localStorage
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 微服务核心架构梳理
  • 微信开放平台全网发布【失败】的几点排查方法
  • 小试R空间处理新库sf
  • 写代码的正确姿势
  • 移动端唤起键盘时取消position:fixed定位
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​力扣解法汇总1802. 有界数组中指定下标处的最大值
  • ​力扣解法汇总946-验证栈序列
  • #pragma pack(1)
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • (2)STL算法之元素计数
  • (4)logging(日志模块)
  • (C语言)逆序输出字符串
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (pojstep1.1.2)2654(直叙式模拟)
  • (分类)KNN算法- 参数调优
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (理论篇)httpmoudle和httphandler一览
  • (循环依赖问题)学习spring的第九天
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (转)mysql使用Navicat 导出和导入数据库