C++ 智能指针 unique_ptr shared_ptr weak_ptr小练习

news2025/2/23 21:20:52

智能指针是 C++11 引入的一项重要特性,它可以帮助我们管理动态分配的内存,自动释放内存,避免内存泄漏和悬空指针的问题。智能指针有三种常用类型:std::unique_ptrstd::shared_ptrstd::weak_ptr

为了帮助你熟悉智能指针的使用,下面是一些练习题,涵盖了智能指针的基本用法以及一些常见的应用场景。

练习 1:使用 std::unique_ptr

任务:创建一个 std::unique_ptr,用于管理一个动态分配的 int 类型的内存,并打印其值。

#include <iostream>
#include <memory>

int main() {
    // 创建一个unique_ptr来管理动态分配的内存
    // 请补充代码,使用 std::make_unique 创建一个 unique_ptr
    return 0;
}

提示:使用 std::make_unique 来创建 std::unique_ptr,并访问其管理的对象。


练习 2:std::unique_ptr 的转移所有权

任务:展示如何通过 std::move 转移 std::unique_ptr 的所有权。

#include <iostream>
#include <memory>

void print_value(std::unique_ptr<int> ptr) {
    std::cout << "Value: " << *ptr << std::endl;
}

int main() {
    std::unique_ptr<int> ptr1 = std::make_unique<int>(10);
    
    // 转移所有权到 ptr2
    std::unique_ptr<int> ptr2 = std::move(ptr1);
    
    // 确保 ptr1 已经不再拥有资源,尝试解引用 ptr1 会导致错误
    if (ptr1 == nullptr) {
        std::cout << "ptr1 is now null." << std::endl;
    }

    // 打印 ptr2 中的值
    print_value(std::move(ptr2));
    
    return 0;
}

提示:使用 std::move 来转移 std::unique_ptr 的所有权。转移后,ptr1 会变为空指针,无法再访问其管理的资源。


练习 3:使用 std::shared_ptr

任务:使用 std::shared_ptr 来管理一个动态分配的 int 类型的内存,并展示多个 shared_ptr 指向同一内存时,引用计数的变化。

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(20);
    
    // 创建 ptr2,并共享 ptr1 管理的内存
    std::shared_ptr<int> ptr2 = ptr1;
    
    std::cout << "ptr1's value: " << *ptr1 << std::endl;
    std::cout << "ptr2's value: " << *ptr2 << std::endl;

    // 输出引用计数
    std::cout << "Reference count: " << ptr1.use_count() << std::endl;
    
    return 0;
}

提示std::shared_ptr 允许多个指针共享同一块内存,它会自动管理引用计数。当引用计数为 0 时,内存会自动释放。


练习 4:std::shared_ptr 的循环引用问题

任务:通过一个简单的类和 std::shared_ptr,模拟一个循环引用的情况,并展示为什么会导致内存泄漏。

#include <iostream>
#include <memory>

class A;
class B;

class A {
public:
    std::shared_ptr<B> b;
    ~A() { std::cout << "A destroyed!" << std::endl; }
};

class B {
public:
    std::shared_ptr<A> a;
    ~B() { std::cout << "B destroyed!" << std::endl; }
};

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();
    
    a->b = b;
    b->a = a;
    
    // 在这里,a 和 b 的引用计数会永远不为 0,导致内存无法释放
    return 0;
}

提示:循环引用导致两个 shared_ptr 永远无法释放内存,因为它们互相引用,引用计数始终大于 0。可以通过使用 std::weak_ptr 来解决这个问题。


练习 5:使用 std::weak_ptr 打破循环引用

任务:修改上一题的代码,使用 std::weak_ptr 来解决循环引用的问题。

#include <iostream>
#include <memory>

class A;
class B;

class A {
public:
    std::shared_ptr<B> b;
    ~A() { std::cout << "A destroyed!" << std::endl; }
};

class B {
public:
    std::weak_ptr<A> a;  // 使用 weak_ptr 打破循环引用
    ~B() { std::cout << "B destroyed!" << std::endl; }
};

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();
    
    a->b = b;
    b->a = a;  // 使用 weak_ptr 避免循环引用

    return 0;
}

提示:使用 std::weak_ptr 来避免循环引用问题,weak_ptr 不增加引用计数,因此不会导致资源无法释放。


练习 6:std::shared_ptr 和自定义删除器

任务:使用 std::shared_ptr 创建一个自定义删除器,删除时打印一条消息。

#include <iostream>
#include <memory>

void custom_deleter(int* ptr) {
    std::cout << "Deleting pointer: " << ptr << std::endl;
    delete ptr;
}

int main() {
    // 创建 shared_ptr 时传入自定义删除器
    std::shared_ptr<int> ptr = std::shared_ptr<int>(new int(10), custom_deleter);
    
    std::cout << "Value: " << *ptr << std::endl;
    
    return 0;
}

提示std::shared_ptr 允许传入自定义的删除器,用来控制资源的释放方式。在删除 shared_ptr 时,删除器会被调用。


练习 7:std::unique_ptr 和数组

任务:使用 std::unique_ptr 来管理动态分配的数组。

#include <iostream>
#include <memory>

int main() {
    // 创建一个unique_ptr来管理动态分配的数组
    std::unique_ptr<int[]> arr = std::make_unique<int[]>(5);
    
    // 给数组赋值并打印
    for (int i = 0; i < 5; ++i) {
        arr[i] = i * 10;
    }
    
    for (int i = 0; i < 5; ++i) {
        std::cout << arr[i] << " ";
    }
    
    return 0;
}

提示std::unique_ptr 可以用于管理数组,创建时使用 std::make_unique<T[]> 来分配动态数组。


练习 8:std::shared_ptr 与自定义类型

任务:创建一个自定义类并使用 std::shared_ptr 来管理它的实例。

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "MyClass Constructor" << std::endl; }
    ~MyClass() { std::cout << "MyClass Destructor" << std::endl; }
};

int main() {
    std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>();
    std::cout << "Shared pointer in scope" << std::endl;
    
    return 0;
}

提示std::shared_ptr 可以用于管理自定义类型的对象。使用 std::make_shared 创建并管理对象实例。


这些练习将帮助你理解和掌握 C++ 中智能指针的使用,特别是 std::unique_ptrstd::shared_ptr 的基本概念、引用计数、资源管理,以及如何避免常见的内存管理问题(如循环引用)。

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

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

相关文章

内容中台架构下智能推荐系统的算法优化与分发策略

内容概要 在数字化内容生态中&#xff0c;智能推荐系统作为内容中台的核心引擎&#xff0c;承担着用户需求与内容资源精准匹配的关键任务。其算法架构的优化路径围绕动态特征建模与多模态数据融合展开&#xff0c;通过深度强化学习技术实现用户行为特征的实时捕捉与动态更新&a…

最新版IDEA下载安装教程

一、下载IDEA 点击前往官网下载 或者去网盘下载 点击前往百度网盘下载 点击前往夸克网盘下载 进去后点击IDEA 然后点击Download 选择自己电脑对应的系统 点击下载 等待下载即可 二、安装IDEA 下载好后双击应用程序 点击下一步 选择好安装目录后点击下一步 勾选这两项后点击…

DeepSeek最新开源动态:核心技术公布

2月21日午间&#xff0c;DeepSeek在社交平台X发文称&#xff0c;从下周开始&#xff0c;他们将开源5个代码库&#xff0c;以完全透明的方式与全球开发者社区分享他们的研究进展。并将这一计划定义为“Open Source Week”。 DeepSeek表示&#xff0c;即将开源的代码库是他们在线…

【R语言】绘图

一、散点图 散点图也叫X-Y图&#xff0c;它将所有的数据以点的形式展现在坐标系上&#xff0c;用来显示变量之间的相互影响程度。 ggplot2包中用来绘制散点图的函数是geom_point()&#xff0c;但在绘制前需要先用ggplot()函数指定数据集和变量。 下面用mtcars数据集做演示&a…

Linux基本指令(三)+ 权限

文章目录 基本指令grep打包和压缩zip/unzipLinux和windows压缩包互传tar&#xff08;重要&#xff09;Linux和Linux压缩包互传 bcuname -r常用的热键关机外壳程序 知识点打包和压缩 Linux中的权限用户权限 基本指令 grep 1. grep可以过滤文本行 done用于标记循环的结束&#x…

容器化部署tomcat

容器化部署tomcat 需求在docker容器中部署tomcat,并通过外部机器访问tomcat部署的项目 容器化部署要先装好docker容器(docker安装配置) 实现步骤&#xff1a; 拉取tomcat docker pull tomcat用于列出本地Docker主机上存储的所有镜像 docker images在root目录里面创建tomc…

vscode软件中引入vant组件

一、vant简介 Vant 是一个轻量、可靠的移动端组件库&#xff0c;于 2017 年开源。 目前 Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本&#xff0c;并由社区团队维护 React 版本和支付宝小程序版本。 官网&#xff1a;介绍 - Vant Weapp 里面的快速上手的教程&a…

DeepSeek vs ChatGPT:AI 领域的华山论剑,谁主沉浮?

一、引言 在当今科技飞速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;已然成为推动各领域变革的核心力量。而在人工智能的众多分支中&#xff0c;自然语言处理&#xff08;NLP&#xff09;因其与人类日常交流和信息处理的紧密联系&#xff0c;成为了最受瞩目的领…

Ubuntu 22.04 Install deepseek

前言 deepseekAI助手。它具有聊天机器人功能&#xff0c;可以与用户进行自然语言交互&#xff0c;回答问题、提供建议和帮助解决问题。DeepSeek 的特点包括&#xff1a; 强大的语言理解能力&#xff1a;能够理解和生成自然语言&#xff0c;与用户进行流畅的对话。多领域知识&…

如何将公钥正确添加到服务器的 authorized_keys 文件中以实现免密码 SSH 登录

1. 下载密钥文件 2. RSA 解析 将 id_ed25519 类型的私钥转换为 RSA 类型&#xff0c;要将 ED25519 私钥转换为 RSA 私钥&#xff0c;需要重新生成一个新的 RSA 密钥对。 步骤&#xff1a; 生成新的 RSA 密钥对 使用 ssh-keygen 来生成一个新的 RSA 密钥对。比如&#xff0c;执…

光明谷推出AT指令版本的蓝牙音箱SOC 开启便捷智能音频开发新体验

前言 在蓝牙音箱市场竞争日益激烈的当下&#xff0c;开发一款性能卓越且易于上手的蓝牙音箱&#xff0c;成为众多厂商追求的目标。而光明谷科技有限公司推出的 AT 指令版本的蓝牙音箱 SOC&#xff0c;无疑为行业带来了全新的解决方案&#xff0c;以其诸多独特卖点&#xff0c;迅…

TIP: Flex-DLD

Article: Flex-DLD: Deep Low-Rank Decomposition Model With Flexible Priors for Hyperspectral Image Denoising and Restoration, 2024 TIP. 文章的主要思想是用network来学low-rank decomposition的两个matrix&#xff08;input是random input&#xff09;. 文章的framew…

MFC开发:如何创建第一个MFC应用程序

文章目录 一、概述二、MFC 的主要组件三、创建一个MFC窗口四、控件绑定消息函数 一、概述 MFC 是微软提供的一个 C 类库&#xff0c;用于简化 Windows 应用程序的开发。它封装了 Windows API&#xff0c;提供面向对象的接口&#xff0c;帮助开发者更高效地创建图形用户界面&am…

Java与C语言中取模运算符%的区别对比

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: Java 文章目录 &#x1f4af;前言&#x1f4af;C语言中的取模运算符 %基本行为示例 注意事项示例&#xff1a;负数取模 &#x1f4af;Java中的取模运算符 %基本行为示例 对浮点数的支持示例&#xff1a;浮点数取模 符…

Zabbix 7.2实操指南:基于OpenEuler系统安装Zabbix 7.2

原文出处&#xff1a;乐维社区 部署环境 openEuler 22.03 LTS PHP 8.0 Apache Mysql 8.0 MySQL数据库 6.0 以上版本需要安装mysql8.0以上版本的数据库&#xff08;以mysql为例子&#xff09;。 欧拉系统自带 mysql8.0 的源&#xff0c;无需要安装额外的源。 安装mysql …

Win11 24h2 不能正常使用ensp的问题(已解决)

因为Win11 24h2的内核大小更改&#xff0c;目前virtualbox在7.1.4中更新解决了。所以Win11 24H2系统版本无法使用 5.x.xx的virtualbox版本&#xff0c;virtualbox对于这个5.x.xx版本早已停止维护&#xff0c;所以这个以后不会有调整。 对应的报错代码是 virtualbox错误代码&…

蓝桥杯——按键

一&#xff1a;按键得原理图 二&#xff1a;按键的代码配置 step1 按键原理图对应引脚配置为输入状态 step2 在GPIO中将对应引脚设置为上拉模式 step3 在fun.c中写按键扫描函数 写完后的扫描函数需放在主函数中不断扫描 扫描函数主要通过两个定义变量的值来判断&#xf…

Linux环境基础开发工具的使用(三)

五、Linux项目自动化构建工具-make/Makefile make&#xff1a;是一条指令。 makefile&#xff1a;是一个当前目录下的文件。 第一行&#xff1a;依赖关系。 第二行&#xff1a;依赖方法。 clean是空依赖关系。 编译文件清理 背景 会不会写makefile&#xff0c;从一个侧面说…

electron提升软件运行权限,以管理员权限运行

大家有任何想法&#xff0c;都可以联系博主沟通。 本系列为实战文章&#xff0c;最终实现的桌面工具软件&#xff0c;获取方式&#xff1a;百度网盘地址&#xff1a;https://pan.baidu.com/s/1yrl0jYpti7QCn8CHBRT2lw?pwd1234 正文开始 前言一、提升electron运行权限的三种方…

安科瑞能源物联网平台助力企业实现绿色低碳转型

安科瑞顾强 随着全球能源结构的转型和“双碳”目标的推进&#xff0c;能源管理正朝着智能化、数字化的方向快速发展。安科瑞电气股份有限公司推出的微电网智慧能源管理平台&#xff08;EMS 3.0&#xff09;&#xff0c;正是这一趋势下的创新解决方案。该平台集成了物联网&…