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

每日学习记录003:(C++)unique_ptr和shared_ptr

每日学习记录003:(C++)unique_ptr和shared_ptr

在C++中,unique_ptr和shared_ptr都是智能指针,它们为动态内存管理提供了更安全、更方便的方式。

一、unique_ptr的特点

(一)独占所有权

unique_ptr拥有它所指向对象的独占所有权。这意味着在同一时间,只有一个unique_ptr可以指向特定的对象。
例如:

#include <memory>
#include <iostream>

int main() {
    std::unique_ptr<int> ptr1 = std::make_unique<int>(10);
    std::cout << *ptr1 << std::endl;
    // 以下代码会编译错误,因为不能将一个已经被unique_ptr拥有的对象再交给另一个unique_ptr
    // std::unique_ptr<int> ptr2 = ptr1;
    std::unique_ptr<int> ptr2 = std::move(ptr1); // 使用std::move将ptr1的所有权转移给ptr2
    std::cout << *ptr2 << std::endl;
    std::cout << *ptr1 << std::endl;//这里在运行时会报错:Segmentation fault (core dumped),因为ptr1已经不再拥有对象了

    return 0;
}

在这个例子中,ptr1最初拥有一个值为10的int对象。当我们想要将这个对象的所有权转移给ptr2时,不能直接赋值,而是需要使用std::move。这体现了unique_ptr的独占性。
然后注意,在move后,*ptr会报错:Segmentation fault (core dumped),因为ptr1已经不再拥有对象了,debug中也可以看到,move后ptr1就指向地址0了
在这里插入图片描述

(二)对象生命周期管理

当unique_ptr被销毁(例如超出作用域)时,它所指向的对象也会被自动销毁。
例如:

#include <memory>
#include <iostream>

struct MyClass {
    MyClass() { std::cout << "MyClass类对象的构造函数被调用" << std::endl; }
    ~MyClass() { std::cout << "MyClass类对象的析构函数被调用" << std::endl; }
};

void function() {
    std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
}

int main() {
    function();
    return 0;
}

在function函数中,创建了一个MyClass类型的对象,通过unique_ptr来管理。当function函数结束时,ptr超出作用域,MyClass对象的析构函数会被自动调用。

二、shared_ptr的特点

(一)共享所有权

多个shared_ptr可以共享指向同一个对象的所有权。
例如:

#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(20);
    std::shared_ptr<int> ptr2 = ptr1;
    std::cout << *ptr1 << " " << *ptr2 << std::endl;
    return 0;
}

这里ptr1和ptr2都指向同一个int对象,并且可以正常访问该对象的值。

(二)引用计数

shared_ptr内部使用引用计数来管理对象的生命周期。
当一个新的shared_ptr开始共享对象时,引用计数加1;当一个shared_ptr不再指向该对象(例如被重新赋值或者超出作用域)时,引用计数减1。当引用计数为0时,对象才会被销毁。
例如:

#include <memory>
#include <iostream>

struct MyClass {
    MyClass() { std::cout << "MyClass类对象的构造函数被调用" << std::endl; }
    ~MyClass() { std::cout << "MyClass类对象的析构函数被调用" << std::endl; }
};

int main() {
    std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
    {
        std::shared_ptr<MyClass> ptr2 = ptr1;
        std::cout << "Inside inner block, reference count: " << ptr1.use_count() << std::endl;
    }
    std::cout << "Outside inner block, reference count: " << ptr1.use_count() << std::endl;
    return 0;
}

在这个例子中,在内部代码块中,ptr1和ptr2共享MyClass对象,引用计数为2。当内部代码块结束时,ptr2超出作用域,引用计数减为1。

小测验

下面的代码的打印结果是什么?

shared_ptr<Account> p1 = make_shared<Account>("Alice", 1000.0);
shared_ptr<Account> p2 = p1;
shared_ptr<Account> p3 = p2;

cout << p1.use_count() <<endl;
cout << p2.use_count() <<endl;
cout << p3.use_count() <<endl;

答案在最下面

三、unique_ptr和shared_ptr的区别

(一)所有权模式

unique_ptr是独占所有权,而shared_ptr是共享所有权。
如前面的示例所示,unique_ptr不能简单地复制来共享对象,而shared_ptr可以方便地共享。

(二)内存开销

一般情况下,unique_ptr的内存开销比shared_ptr小。
因为shared_ptr需要额外的空间来存储引用计数,而unique_ptr不需要。

(三)使用场景

当对象的所有权明确为独占时,应该使用unique_ptr,例如在函数内部创建一个对象,并且不需要在函数外部共享这个对象时。
当对象需要在多个部分之间共享时,使用shared_ptr比较合适,例如在不同的类或者模块之间共享一个对象。
小测验里,结果都是3,因为是shared_ptr 指向的是一个东西


http://www.kler.cn/a/401111.html

相关文章:

  • 深入解析大带宽服务器:性能优势与选择指南
  • Nginx Spring boot指定域名跨域设置
  • 【网络云计算】2024第48周-技能大赛-初赛篇
  • 学习日志012--python中多进程,多线程
  • WebRTC实现双端音视频聊天(Vue3 + SpringBoot)
  • 高斯数据库Postgresql死锁和锁表解决方法
  • ftrack 24.10全面升级:Autodesk Flame集成与多项新功能性能改进将发布
  • spring boot启动停止重启脚本
  • 视觉SLAM--经典视觉SLAM框架
  • MySQL数据库-SQLyoung的使用
  • 【金融风控项目-07】:业务规则挖掘案例
  • 播放器开发之ffmpeg 硬件解码方案
  • 【一文了解】C#基础-数组
  • leetcode 面试150 之随机链表的复制
  • Oracle 19c修改pga报ORA-00093、ORA-01078错进行分析处理
  • 美国人工智能国家安全备忘录核心解读(上)
  • DimensionX:单图生成任意的3d/4d视图
  • 3. 用Ruby on Rails创建一个在线商城
  • Ruby编程语言全景解析:从基础到进阶
  • linux中如何退出python
  • excel打开csv文件乱码的问题
  • 毛选阅读第一卷
  • 1Panel 推送 SSL 证书到阿里云、腾讯云
  • Spring Boot汽车资讯:科技与速度的新境界
  • 【LeetCode 题】只出现一次的数字--其余数字都出现3次
  • 打通 Dify 和 ComfyUI 的绘画尝试