C++智能指针

面试的时候被问到智能指针,虽然回答出来了,但是很多细节没有讲清楚,决定看看资料,重新学一下C++智能指针。

智能指针相关面试题

关于智能指针整理的面试题:

  • 什么时候用裸指针比智能指针更好:
    • 在函数传递的时候,不要传递shared_ptr本身,而是用原始指针。因为会有性能损失,原子操作的自增自减等。
  • 智能指针shared_ptr线程安全吗
  • shared_ptr引用计数的实现了解吗
  • 多线程下shared_ptr会被析构两次吗
  • unique_ptr在项目哪里用到
  • weak_ptr了解吗
  • weak_ptr的expired是线程安全嘛?
  • shared_ptr和weak_ptr如何配合使用?

智能指针的基本介绍

三种智能指针的用法

  • shared_ptr:允许多个指针指向一个对象
  • unique_ptr:独占的指向所指对象。unique_ptr 更轻量,所以尽量使用unique_ptr。
  • weak_ptr:弱引用,指向shared_ptr所管理的对象

智能指针主要用于管理在堆上分配的内存(即管理分配在堆上的对象),但是智能指针本身存在栈

在初始化一个智能指针的时候,用普通指针或者new出来的地址初始化是没有问题的。
但是如果指向某个内存Ox00000001的智能指针ptr1已经存在,同时还有有个一个普通指针p1指向,当你用普通指针p1(或者ptr1.get())初始化另一个智能指针ptr2时,就有问题了:ptr1和ptr2的引用计数都会是1,他们是分别计数的,当某个智能指针离开其作用域,会导致另一个智能指针也失效。
总结来说就是:

  • 在某个内存第一次被智能指针初始化的时候,用普通指针或者new出来的地址初始化是没有问题的。
  • 但是当指向某个内存已经有智能指针指向时,只能用该智能指针初始化

3. 线程安全

3.1. shared_ptr线程安全的讨论

shared_ptr的线程安全隐患

主要是以下几个方面:
(1) 引用计数的加减操作是线程安全。
(2) 修改shared_ptr指向(写操作) 不是线程安全。

3.1.1 引用计数的线程安全

shared_ptr中除了有一个指针,指向所管理数据的地址。还有一个指针执行一个控制块的地址,里面存放了所管理数据的数量(常说的引用计数)、weak_ptr的数量、删除器、分配器等。

也就是说对于引用计数这一变量的存储,是在堆上的,多个shared_ptr的对象都指向同一个堆地址。在多线程环境下,管理同一个数据的shared_ptr在进行计数的增加或减少的时候是线程安全的吗?

答案是肯定的,这一操作是原子操作(不会被线程调度机制打断的操作)。
结论:共享引用计数的不同的shared_ptr被多个线程写,是线程安全的。

3.1.2 对shared_ptr写操作的线程安全

场景一:同一个shared_ptr被多个线程写
先给出结论:此时不是线程安全的。

首先回顾一下shared_ptr指针的内部结构,包含两个重要的变量:ptr指针和引用计数指针。

对于shared_ptr的复制则分为两个步骤:

  • 复制ptr指针
  • 复制引用计数指针

所以,由于 shared_ptr 有两个数据成员,读写操作不能原子化,因此不少线程安全的。

可以参考例子:
陈硕:智能指针的探讨
年年年年:智能指针与线程安全

场景二:同一个shared_ptr被多个线程读;

仅仅是读取,而未修改数据所以给出结论:
同一个shared_ptr被多个线程“读”是安全的;

3.1.3 shared_ptr线程安全的总结

shared_ptr的线程安全总结如下。(shared_ptr)的引用计数由于本身是原子操作所以是安全且无锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原子化。shared_ptr 的线程安全级别和内建类型、标准库容器、std::string 一样,即:

  • 同一个shared_ptr被多个线程“读”是安全的;
  • 同一个shared_ptr被多个线程“写”是不安全的;
  • 共享引用计数的不同的shared_ptr被多个线程”写“ 是安全的

请注意,以上是 shared_ptr 对象本身的线程安全级别,不是它管理的对象的线程安全级别。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值