智能指针 c++

C++ 智能指针详解

智能指针是 C++11 引入的内存管理工具,位于 <memory> 头文件中,用于自动管理动态分配的内存,防止内存泄漏。主要类型如下:


1. std::unique_ptr (独占所有权)
  • 特点:唯一拥有所指对象,不可复制(可移动)
  • 适用场景:独占资源所有权
  • 内存开销:几乎为零(仅包装原始指针)
#include <memory>void unique_ptr_example() {// 创建 unique_ptr (C++14 推荐 make_unique)auto ptr = std::make_unique<int>(42);// 访问对象*ptr = 100;std::cout << *ptr;  // 输出 100// 移动所有权auto ptr2 = std::move(ptr);  // ptr 变为 nullptr// 自定义删除器(处理特殊资源)auto file_deleter = [](FILE* f) { if(f) fclose(f); };std::unique_ptr<FILE, decltype(file_deleter)> file_ptr(fopen("test.txt", "r"), file_deleter);// 离开作用域自动释放内存
}

2. std::shared_ptr (共享所有权)
  • 特点:多个指针共享对象,使用引用计数
  • 适用场景:需要共享所有权的资源
  • 内存开销:控制块(引用计数 + 弱计数)
void shared_ptr_example() {// 创建 shared_ptr (推荐 make_shared)auto ptr1 = std::make_shared<std::string>("Hello");// 共享所有权auto ptr2 = ptr1;  // 引用计数 +1// 查看引用计数std::cout << ptr1.use_count();  // 输出 2// 自定义删除器auto arr_deleter = [](int* p) { delete[] p; };std::shared_ptr<int> arr_ptr(new int[10], arr_deleter);// 离开作用域时自动减少引用计数// 引用计数为0时释放内存
}

3. std::weak_ptr (弱引用)
  • 特点:不增加引用计数,解决循环引用问题
  • 适用场景:打破 shared_ptr 循环引用
  • 用法:需转换为 shared_ptr 访问对象
struct Node {std::shared_ptr<Node> next;std::weak_ptr<Node> prev;  // 使用 weak_ptr 避免循环引用
};void weak_ptr_example() {auto node1 = std::make_shared<Node>();auto node2 = std::make_shared<Node>();node1->next = node2;node2->prev = node1;  // 不会增加引用计数// 访问 weak_ptr 指向的对象if(auto locked = node2->prev.lock()) {// 成功转换为 shared_ptr} else {// 对象已被释放}
}

4. 智能指针对比表
特性unique_ptrshared_ptrweak_ptr
所有权独占共享无(观察者)
是否影响引用计数
复制语义禁用(仅移动)允许允许
内存开销几乎为零控制块(约16-32字节)控制块指针
典型应用场景工厂模式返回值共享数据打破循环引用
线程安全对象访问需同步引用计数原子操作同 shared_ptr

5. 最佳实践与注意事项
  1. 优先使用 make_unique/make_shared

    // 更安全高效(单次内存分配)
    auto ptr = std::make_shared<MyClass>(arg1, arg2);
    
  2. 避免循环引用

    • 父对象用 shared_ptr 持有子对象
    • 子对象用 weak_ptr 引用父对象
  3. 不要混用原始指针

    // 危险操作!
    MyClass* raw = new MyClass();
    std::shared_ptr<MyClass> p1(raw);
    std::shared_ptr<MyClass> p2(raw);  // 会导致双重释放
    
  4. 接口设计原则

    • 函数接收原始指针:不获取所有权
    • 函数接收 unique_ptr:获取所有权
    • 函数返回 unique_ptr:转移所有权
  5. 特殊资源管理

    // 管理数组 (C++17+)
    auto arr = std::make_unique<int[]>(10);// 管理自定义资源
    auto custom_deleter = [](Resource* r) { cleanup(r); };
    std::unique_ptr<Resource, decltype(custom_deleter)> res(new Resource, custom_deleter);
    

6. 性能考虑
  • unique_ptr:几乎无开销,等同于原始指针
  • shared_ptr
    • 控制块分配开销(使用 make_shared 可优化)
    • 原子操作引用计数(约比非原子操作慢10倍)
  • 高频访问场景:考虑 unique_ptr + 移动语义

7. C++17/20 增强
  1. 数组支持

    // C++17 特有
    auto arr = std::make_unique<int[]>(5);
    arr[0] = 10;
    
  2. std::allocate_shared

    // 自定义分配器
    CustomAllocator alloc;
    auto ptr = std::allocate_shared<MyClass>(alloc, args...);
    
  3. std::weak_from_this

    class MyClass : public std::enable_shared_from_this<MyClass> {
    public:std::weak_ptr<MyClass> weak_ref() {return weak_from_this();  // C++17}
    };
    

8. 常见错误
// 错误1:返回局部对象的智能指针
std::shared_ptr<int> create() {int value = 42;return std::make_shared<int>(value);  // 正确// return &value;  // 灾难!
}// 错误2:循环引用
struct A {std::shared_ptr<B> b;  // 应使用 weak_ptr
};
struct B {std::shared_ptr<A> a;  // 应使用 weak_ptr
};// 错误3:误用 get() 管理生命周期
void process(int* raw) { /*...*/ }auto ptr = std::make_unique<int>(10);
process(ptr.get());  // 安全
delete ptr.get();    // 灾难!

智能指针是现代 C++ 内存管理的核心工具,正确使用可消除 90% 以上的内存管理问题。

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

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

相关文章

Python应用八股文

大家好!在 Python 学习的道路上&#xff0c;掌握一些基础知识要点至关重要&#xff0c;这些要点常被称为“Python 八股”。以下是对它们的简易总结&#xff0c;帮助你快速回顾和巩固 Python 的核心概念。 一、数据结构 列表&#xff08;List&#xff09;&#xff1a;有序可变序…

【技术深度】领码SPARK破解微服务数据依赖困局:架构设计与实践指南

——深度解析分布式数据冗余与异步消息机制&#xff0c;驱动企业数字化转型加速 ✨ 核心摘要 本文从技术架构与工程实现的角度&#xff0c;系统讲解领码SPARK融合平台如何精准解决微服务架构下数据依赖“卡脖子”问题。通过设计高效的数据冗余模型和完善的异步消息更新机制&am…

关于前端的防抖和节流

给我解释下 前端开发中的防抖和节流 并举个具体的例子 防抖&#xff08;Debounce&#xff09;与节流&#xff08;Throttle&#xff09;详解 在前端开发中&#xff0c;防抖&#xff08;Debounce&#xff09; 和 节流&#xff08;Throttle&#xff09; 是两种优化高频触发事件的…

React-router 多类型历史记录栈

react-router 为了满足开发者更多路由历史存储场景&#xff0c;提供了以下几种模式&#xff1a; 浏览器原生历史记录 浏览器 hash 内存型 服务端记录 以上实现分别对应于一下 API 实现&#xff1a; createBrowserRouter&#xff1a;浏览器提供的历史管理。 createHashRou…

java设计模式[3]之结构型模式

文章目录 一 代理模式1.1 静态代理1.1.1 静态代理的结构1.1.2 静态代理的特点1.1.3 静态代理的应用场景1.1.4 静态代理的案例代码 1.2 JDK动态代理1.2.1 JDK动态代理概述1.2.2 JDK动态代理案例代码1.2.3 JDK动态代理的应用场景1.2.4 JDK动态代理的特点1.2.5 与创建型模式的区别…

鸿蒙Harmony测试-wukong稳定性工具(类似Android的Monkey测试)

一、功能介绍 wukong是系统自带的一种命令行工具&#xff0c;支持Ability的随机事件注入、控件注入、异常捕获、报告生成和对Ability数据遍历截图等特性。通过模拟用户行为&#xff0c;对系统或应用进行稳定性压力测试。wukong分为随机测试、专项测试和专注测试。 随机测试是指…

从零学起VIM

前言 笔者早年刚入行的时候就接触过Vim,当时还是真正的菜鸟&#xff0c;带我的师父是一个华为骨干员工&#xff0c;犹记得他给我指导如何保存并关闭文本&#xff1a;按Esc&#xff0c;然后输入:wq。还记得自己打开Vim编辑器&#xff0c;一个字符都敲不进去&#xff0c;然后问旁…

不依赖rerank 模型排序通过使用 PostgreSQL 中的 pgvector 与 tsearch2 函数进行混合搜索提高召回率

前言 在向量搜索中&#xff0c;召回率是一个关键指标&#xff0c;它衡量搜索结果的相关性。然而&#xff0c;提高召回率往往会牺牲其他指标&#xff0c;如索引大小或查询延迟。为了平衡这些权衡&#xff0c;混合搜索技术应运而生。本文将介绍如何在 PostgreSQL 中结合 pgvecto…

Uniapp 跨平台开发框架全面解析:一次开发,多端运行

在移动互联网时代&#xff0c;开发者面临着一个重要挑战&#xff1a;如何高效地开发出能在多个平台&#xff08;iOS、Android、Web、小程序等&#xff09;上运行的应用&#xff1f;传统的原生开发方式需要为每个平台单独编写代码&#xff0c;导致开发周期长、维护成本高。而 Un…

ios如何把H5网页变成主屏幕webapp应用

一、将 H5 页面添加到主屏幕的步骤 打开 Safari 浏览器 在 iPhone 上打开 Safari 浏览器&#xff0c;访问目标网页&#xff08;H5 页面&#xff09;。 点击分享按钮 在 Safari 浏览器底部点击 “分享” 图标&#xff08;箭头向上的按钮&#xff09;。 添加到主屏幕 在分享菜单…

Node.js 项目启动命令大全 (形象版)

文章目录 Node.js 项目启动命令大全 &#x1f31f;✨&#xff08;形象版&#xff09;一、&#x1f50d; 如何查看项目启动命令&#xff08;魔法书目录&#xff09;package.json scripts 参数详解开发相关脚本测试相关脚本构建相关脚本代码质量相关脚本最佳实践 二、&#x1f68…

爱普特APT32F1104C8T6单片机 高抗干扰+硬件加密双保障

爱普特APT32F1104C8T6单片机深度解析 1. 产品定位 APT32F1104C8T6 是爱普特半导体&#xff08;APT&#xff09;推出的 32位高性能经济型单片机&#xff0c;基于 ARM Cortex-M0内核&#xff0c;采用 LQFP48封装&#xff0c;主打 高性价比、低功耗、强抗干扰&#xff0c;是替代进…

使用uni-app ios 打包流程

配置几个步骤即可 1、打包ios需要BundleID ID 2、证书私钥密码 3、信任文件证书文件 4、私钥证书 5、打包 6、获取打包后的ipa文件 7、通过爱思助手安装到iso手机上 8、完成 1、下载&#xff1a;App Uploader去获取我们想要的证书私钥等文件 2、下载完成解压后的文件如下打…

仿muduo库实现并发服务器

1.实现目标 仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器&#xff1a; 通过实现高并发服务器的组件&#xff0c;可以快速实现一个高并发服务器的搭建&#xff0c;并且&#xff0c;通过组内不同应用层协议的支持&#xff0c;可以快速完成高性能服务器的搭建…

迭代器模式:集合遍历的统一之道

引言&#xff1a;集合遍历的演进之路 在软件开发中&#xff0c;集合遍历是我们每天都要面对的基础操作。从最初的数组索引遍历到现代的流式处理&#xff0c;我们经历了&#xff1a; #mermaid-svg-KwTr9k8JgbwRTDhU {font-family:"trebuchet ms",verdana,arial,sans-…

Spring Security OAuth2 组件

我们来系统地讲解一下 Spring Security OAuth2 这个强大的组件。我会从概念、作用、核心组件&#xff0c;以及实际应用场景来为你剖析。 1. 什么是 Spring Security OAuth2&#xff1f; 简单来说&#xff0c;Spring Security OAuth2 是 Spring Security 框架的一个模块&#…

Redis的持久化功能

Redis的持久化功能能够将内存中的数据保存到磁盘&#xff0c;从而在重启后恢复数据。下面为你详细介绍Redis的两种主要持久化方式及其配置方法。 RDB&#xff08;Redis Database&#xff09;持久化 RDB持久化是通过生成某个时间点的数据集快照来实现的。它具有高性能的特点&a…

Chrome 将成为下一个 IE6

最近在技术圈刷到一个帖子&#xff0c;说&#xff1a;“Chrome 就快变成新的 IE6 了。” 乍一看有点危言耸听&#xff0c;但你一细品&#xff0c;发现还真挺像回事。 想当年&#xff1a;IE6 是怎么垮的&#xff1f; IE6 当年多风光&#xff1f;全球市场份额一度超过 90%&#…

Redis 配置文件详解redis.conf 从入门到实战

一、redis.conf 是什么&#xff1f; Redis 的配置文件&#xff08;默认命名为 redis.conf&#xff0c;Redis 8.0 之后改为 redis-full.conf&#xff09;控制着服务运行的各项参数。该文件采用以下结构&#xff1a; 指令名 参数1 参数2 ... 参数N例如&#xff1a; replicaof …

autoware docker的安装

前言 官方的安装说明&#xff1a; 官方的安装说明 安装前&#xff0c;请确认安装的硬件&#xff1a; CPU with 8 cores16GB RAM[Optional] NVIDIA GPU (4GB RAM) 满足需求 1. 安装软件依赖 这一步主要是安装三个软件&#xff1a; DockerNVIDIA Container Toolkit (pref…