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

59 C++ 现代C++编程艺术8-智能指针

C++ 现代C++编程艺术8-智能指针

文章目录

  • C++ 现代C++编程艺术8-智能指针
    • 一 智能指针原理
    • 二、`unique_ptr`独占指针(独占所有权)
    • 三、`shared_ptr`共享指针(共享所有权)
    • 四、`weak_ptr`弱引用指针(观察者指针)
    • 五、 std::make_shared内存分配
    • 六、 智能指针的高级用法
    • 七、 选择智能指针的准则

一 智能指针原理

裸指针: 原生指针,int *p = new int(10)

  • 提前释放和忘记释放都可造成错误。

智能指针: 用类模板对指针进行自动管理。

  1. 智能指针原理
    用简单的示例来说明智能指针的原理

    #include <iostream>template<typename Ty>
    class Auto_Ptr {
    public://不能进行赋值,还能通过构造函数来初始化explicit Auto_Ptr(Ty* ptr):ptr(ptr){}// 禁止拷贝构造和赋值Auto_Ptr(const Auto_Ptr&) = delete;Auto_Ptr& operator=(const Auto_Ptr&) = delete;~Auto_Ptr(){if(nullptr != ptr){delete ptr;ptr = nullptr;    // 避免悬空指针 std::cout<<"指针已释放!"<<std::endl;}}//指针取值操作Ty& operator*(){return *ptr;}//->成员访问指针操作符Ty* operator->(){return ptr;}private:Ty* ptr;
    };// 定义一个测试类,用于演示->操作符
    class TestClass {
    public:int value;std::string name;void printInfo() {std::cout << "Name: " << name << ", Value: " << value << std::endl;}
    };int main() {Auto_Ptr<int> dat(new int(10));std::cout<<*dat<<std::endl;//输出: 10 指针已释放!// 类类型使用示例 Auto_Ptr<TestClass> objPtr(new TestClass());// 使用->操作符访问成员变量 objPtr->value = 42;objPtr->name = "智能指针测试";// 使用->操作符调用成员函数 objPtr->printInfo(); //输出: Name: 智能指针测试, Value: 42// 也可以这样使用,但不太常见(*objPtr).value = 100;(*objPtr).printInfo();//输出: Name: 智能指针测试, Value: 100// 指针已释放return 0;
    }
    

二、unique_ptr独占指针(独占所有权)

▶ 特点:

  • 唯一所有权:同一时间只能有一个unique_ptr指向资源,独占所有权,不能复制,只能移动

  • 零额外开销:无引用计数机制,性能接近裸指针

  • 支持自定义删除器(如管理文件句柄、网络连接等)

  • 适用于资源独占场景
    ▶ 示例代码:

    #include <iostream>
    #include <memory>class TestClass {
    public:int value;std::string name;void printInfo() {std::cout << "Name: " << name << ", Value: " << value << std::endl;}
    };int main() {auto ptr = std::make_unique<int>(42);  // C++14推荐创建方式 std::unique_ptr<TestClass> obj(new TestClass());// 使用指针 obj->printInfo();(*obj).printInfo();// 所有权转移 auto newOwner = std::move(ptr);  // 原ptr变为nullptr // 管理数组 auto arr = std::make_unique<int[]>(5);arr[0] = 10;// 自定义删除器(管理文件)std::unique_ptr<FILE, decltype(&fclose)> filePtr(fopen("data.txt", "r"), fclose);// 自动释放内存 
    return 0;
    }
    

三、shared_ptr共享指针(共享所有权)

▶ 特点:

  • 引用计数:多个指针共享资源(多个指针可以共享同一对象),计数归零时自动释放

  • 支持弱引用:需配合weak_ptr打破循环引用

  • 控制块存储计数:推荐用make_shared合并内存分配
    ▶ 示例代码

    #include <iostream>
    #include <memory>class TestClass {
    public:int value;std::string name;void printInfo() {std::cout << "Name: " << name << ", Value: " << value << std::endl;}
    };int main() {auto sp1 = std::make_shared<TestClass>();std::shared_ptr<TestClass> sp2 = sp1;  // 引用计数+1 std::cout << "引用计数: " << sp1.use_count()  << std::endl;//引用计数: 2std::shared_ptr<TestClass> sp3 = sp1;  // 引用计数+1 std::cout << "引用计数: " << sp1.use_count()  << std::endl;//引用计数: 3{std::shared_ptr<TestClass> sp4 = sp1;  // 引用计数+1 std::cout << "引用计数: " << sp1.use_count()  << std::endl;//引用计数: 4}//sp4 离开作用域,引用计数减少 std::cout << "引用计数: " << sp1.use_count()  << std::endl;//引用计数: 3// 循环引用问题(错误示例)struct Node {std::shared_ptr<Node> next;  // 相互持有导致内存泄漏 };auto nodeA = std::make_shared<Node>();auto nodeB = std::make_shared<Node>();nodeA->next = nodeB;nodeB->next = nodeA;// 使用weak_ptr打破循环 struct SafeNode {std::weak_ptr<SafeNode> next;  // 弱引用不增加计数 };// 最后一个shared_ptr销毁时释放对象 
    return 0;
    }
    

四、weak_ptr弱引用指针(观察者指针)

▶ 特点

  • 不拥有所有权:不影响引用计数
  • 必须转换为shared_ptr才能访问对象
  • 提供expired()方法检测资源有效性
  • 用于解决shared_ptr的循环引用问题
    ▶ 示例代码
#include <iostream>
#include <memory>
#include <vector>class TestClass {
public:int value;std::string name;void printInfo() {std::cout << "Name: " << name << ", Value: " << value << std::endl;}
};int main() {auto shared = std::make_shared<int>(100);std::weak_ptr<int> weak = shared;if (!weak.expired()) {if (auto temp = weak.lock()) {  // 转换为shared_ptr *temp = 200;  // 安全访问 }}using Resource = TestClass;// 典型应用:对象池模式 class ObjectPool {std::vector<std::weak_ptr<Resource>> pool;public:std::shared_ptr<Resource> acquire() {for (auto& wp : pool) {if (auto sp = wp.lock()) return sp;}return std::shared_ptr<Resource>(new Resource);}};// 最后一个shared_ptr销毁时释放对象 
return 0;
}

五、 std::make_shared内存分配

基本用法
auto ptr = std::make_shared<Type>(args...);

  • Type 是要创建的对象类型
  • args… 是传递给 Type 构造函数的参数
  1. 使用示例

make_shared通常比直接使用 shared_ptr 构造函数更高效,因为:

  • 它只需要一次内存分配(传统方式需要两次)

  • 它将对象和控制块(包含引用计数等)分配在连续内存中

    //传统方式:
    std::shared_ptr<Widget> spw(new Widget);  // 两次分配:对象和控制块//make_shared 方式:
    auto spw = std::make_shared<Widget>();    // 一次分配 
    
  • 基本类型用法

    auto intPtr = std::make_shared<int>(42);
    std::cout << *intPtr << std::endl;  // 输出: 42
    
  • 类对象用法

    class MyClass {
    public:MyClass(int x, std::string s) : x(x), s(s) {}void print() { std::cout << s << ": " << x << std::endl; }
    private:int x;std::string s;
    };auto objPtr = std::make_shared<MyClass>(10, "value");
    objPtr->print();  // 输出: value: 10
    

六、 智能指针的高级用法

  1. 自定义删除器

    #include <memory>
    #include <iostream>
    #include <cstdio>void fileDeleter(FILE* file) {if (file) {fclose(file);std::cout << "File closed\n";}
    }int main() {// 使用自定义删除器管理文件 std::unique_ptr<FILE, decltype(&fileDeleter)> filePtr(fopen("test.txt",  "r"), fileDeleter);if (filePtr) {char buffer[100];fgets(buffer, 100, filePtr.get()); std::cout << "Read: " << buffer;}// 文件自动关闭return 0;
    }
    
  2. 数组支持

    #include <memory>
    #include <iostream>int main() {// C++11方式 std::unique_ptr<int[]> arr1(new int[5]);// C++14推荐方式 auto arr2 = std::make_unique<int[]>(5);for (int i = 0; i < 5; ++i) {arr1[i] = i * 2;arr2[i] = i * 3;}for (int i = 0; i < 5; ++i) {std::cout << arr1[i] << " " << arr2[i] << "\n";}// 数组自动释放return 0;
    }
    
  3. this转换为shared_ptr

    #include <memory>
    #include <iostream>class MyClass : public std::enable_shared_from_this<MyClass> {
    public:std::shared_ptr<MyClass> getShared() {return shared_from_this();}~MyClass() {std::cout << "MyClass destroyed\n";}
    };int main() {auto ptr = std::make_shared<MyClass>();auto ptr2 = ptr->getShared();std::cout << "Reference count: " << ptr.use_count()  << "\n";//Reference count: 2return 0;
    }
    

七、 选择智能指针的准则

  1. 使用std::unique_ptr

    • 资源只有一个拥有者
    • 需要高效的资源管理
    • 需要将所有权转移到其他对象
  2. 使用std::shared_ptr

    • 资源有多个拥有者
    • 无法预先确定哪个拥有者最后使用资源
  3. 使用std::weak_ptr

    • 需要观察共享资源但不参与生命周期管理
    • 需要打破std::shared_ptr的循环引用
  4. 避免使用裸指针管理资源,优先使用智能指针。

http://www.dtcms.com/a/350411.html

相关文章:

  • 探索量子计算的新前沿
  • 深度学习之第三课PyTorch( MNIST 手写数字识别神经网络模型)
  • Telematics Control Unit(TCU)的系统化梳理
  • 从零开始学习单片机14
  • Fory序列化与反序列化
  • 以正确方式构建AI Agents:Agentic AI的设计原则
  • 技术速递|使用 AI 应用模板扩展创建一个 .NET AI 应用与自定义数据进行对话
  • 【Hadoop】HDFS 分布式存储系统
  • Nuxt.js@4 中管理 HTML <head> 标签
  • 【二叉树 - LeetCode】236. 二叉树的最近公共祖先
  • TAISAW钛硕|TST嘉硕Differential output Crystal Oscillator - TW0692AAAE40
  • [electron]开发环境驱动识别失败
  • 深度学习篇--- ResNet-18
  • ArXiv 每日论文追踪器:自动检索、双语总结、邮件推送、一键建站
  • QML 中 的 Row 和 RowLayout
  • (一)C#基础(异步)
  • 数字图像处理(二)
  • 面向机器人推动与抓取任务自适应算法研究
  • langchain的简单应用案例---(2)使用Memory实现一个带记忆的对话机器人
  • 工作记录 2015-10-29
  • 销售额和营业收入的区别在哪?哪个值应该更大一些?
  • 新项目,如何做成本估算?
  • 本地缓存与 Redis 缓存的区别与实际应用
  • 【OpenAI】ChatGPT-4o-latest 真正的多模态、长文本模型的详细介绍+API的使用教程!
  • 2025软件测试面试题(持续更新)
  • 07-JUnit测试
  • ubuntu 卡到登录页面进不去--实测
  • 陪护系统有哪些功能?
  • 高并发内存池(4)-TLS:Thread Local Storage
  • Vue.nextTick讲解