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

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

智能指针是 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 的基本概念、引用计数、资源管理,以及如何避免常见的内存管理问题(如循环引用)。

相关文章:

  • 【Java基础-49】Java线程池及其基本应用详解
  • 强化学习的数学原理-六、随机近似与随机梯度下降
  • HTML之JavaScript DOM简介
  • Python中的闭包和装饰器
  • 静态时序分析:时钟组间的逻辑独立、物理独立和异步的区别
  • Perplexity AI:通过OpenAI与DeepSeek彻底革新搜索和商业策略
  • 过程监督(Process Supervision)融入到 GRPO (Group Relative Policy Optimization)
  • MT7628基于原厂的SDK包, 修改ra1网卡的MAC方法。
  • 【ORB-SLAM3】鲁棒核函数的阈值设置
  • docker-rss:容器更新的RSS订阅源
  • 卷积与动态特征选择:重塑YOLOv8的多尺度目标检测能力
  • 商汤绝影发布全新端到端自动驾驶技术路线R-UniAD
  • 【Python爬虫(49)】分布式爬虫:在新兴技术浪潮下的蜕变与展望
  • 从0开始:OpenCV入门教程【图像处理基础】
  • 【网络】高级IO
  • sklearn中的决策树
  • Java子类调用父类构造器的应用场景
  • STM32-有关内存堆栈、map文件
  • ROS2 应用:按键控制 MoveIt2 中 Panda 机械臂关节位置
  • golang内存泄漏
  • 价格周报|供需回归僵局,本周生猪均价与上周基本持平
  • 黑灰产工作室为境外诈骗集团养号引流,冒充美女与男性裸聊后敲诈勒索
  • 上汽享道出行完成13亿元C轮融资,已启动港股IPO计划
  • 近4小时会谈、3项联合声明、20多份双边合作文本,中俄元首今年首次面对面会晤成果颇丰
  • 甘肃省政府原副省长赵金云被决定逮捕
  • 牛市早报|国家发改委:今年将推出约3万亿元优质项目,支持民营企业参与