某日二师兄参加XXX科技公司的C++工程师开发岗位第19面:

面试官:什么是智能指针?

二师兄:智能指针是C++11引入的类模板,用于管理资源,行为类似于指针,但不需要手动申请、释放资源,所以称为智能指针。

面试官:C++11引入了哪些智能指针?

二师兄:三种,分别是shared_ptrunique_ptr、和weak_ptr

面试官:说一说三种指针的特征及用途。

二师兄:好的。shared_ptr使用了引用计数(use count)技术,当复制个shared_ptr对象时,被管理的资源并没有被复制,而是增加了引用计数。当析构一个shared_ptr对象时,也不会直接释放被管理的的资源,而是将引用计数减一。当引用计数为0时,才会真正的释放资源。shared_ptr可以方便的共享资源而不必创建多个资源。

二师兄:unique_ptr则不同。unique_ptr独占资源,不能拷贝,只能移动。移动过后的unique_ptr实例不再占有资源。当unique_ptr被析构时,会释放所持有的资源。

二师兄:weak_ptr可以解决shared_ptr所持有的资源循环引用问题。weak_ptr在指向shared_ptr时,并不会增加shared_ptr的引用计数。所以weak_ptr并不知道shared_ptr所持有的资源是否已经被释放。这就要求在使用weak_ptr获取shared_ptr时需要判断shared_ptr是否有效。

struct Boo;
struct Foo{
std::shared_ptr<Boo> boo;
};
struct Boo{
std::shared_ptr<Foo> foo;
};

二师兄:Foo中有一个智能指针指向Goo,而Goo中也有一根智能指针指向Foo,这就是循环引用,我们可以使用weak_ptr来解决这个文通。

Boo boo;
auto foo = boo.foo.lock();
if(foo)
{
//这里通过获取到了foo,可以使用
}else
{
//这里没有获取到,不能使用
}

面试官:好的。智能指针是线程安全的吗?

二师兄:是的。抛开类型T,智能指针是类型安全的。

面试官:为什么?

二师兄:因为智能指针底层使用的引用计数是atomic的原子变量,原子变量在自增自减时是线程安全的,这保证了多线程读写智能指针时是安全的。

面试官:好的。为什么尽量不要使用裸指针初始化智能指针?

二师兄:因为可能存在同一个裸指针初始了多个智能指针,在智能指针析构时会造成资源的多次释放。

面试官:为什么不要从智能指针中返回裸指针呢?

二师兄:是因为如果返回的裸指针被释放了,智能指针持有的资源也失效了,对智能指针的操作是未定义的行为。

面试官:智能指针能够持有数组吗?

二师兄:shread_ptrunique_ptr都可以持有数组。

面试官:那你知道在释放资源的时候两者有什么不同吗?

二师兄:这个暂时还不清楚。。

面试官:可以使用静态对象初始化智能指针吗?

二师兄:让我想想。。不可以,因为静态对象的生命周期和进程一样长,而智能指针的析构的时候会导致静态资源被释放。这会导致未定义的行为。

面试官:如果需要在一个类中实现一个方法,这个方法返回这个类的shread_ptr实例,需要注意哪些东西?

二师兄:需要继承std::enable_shared_from_this类,方法返回shared_from_this()

struct Foo : public std::enable_shared_from_this<Foo>
{
std::shared_ptr<Foo> get_foo()
{
return shared_from_this();
}
};

面试官:为什么不直接返回this指针?

二师兄:额。。。不太清楚,但是这应该是个范式。

面试官:好的,今天的面试结束了,请回去等通知吧。

今天二师兄的表现不错,让我们看看一些回答的不太理想的地方吧。

智能指针是线程安全的吗?

很遗憾,使用不当的时候并不是。

#include <iostream>
#include <memory>
#include <thread>
#include <chrono> struct Foo
{
Foo(int i):i_(i){}
void print() {std::cout << i_ << std::endl;}
int i_;
}; int main(int argc, char const *argv[])
{
{
auto shptr = std::make_shared<Foo>(42);
std::thread([&shptr](){
std::this_thread::sleep_for(std::chrono::seconds(1));
shptr->print();
}).detach();
}
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}
// g++ test.cpp -o test -lpthread
// ./test
// Segmentation fault

当我们向另一个线程传递智能指针的引用时,由于use count并没有加1,在shptr析构时直接销毁了管理的Foo实例,所以在线程中执行shptr->print()会引发coredump

修改起来也很简单,把std::thread([&shptr]()改成std::thread([shptr]()即可。记住,智能指针尽量不要传引用

知道在释放资源的时候shread_ptrunique_ptr有什么不同吗?

这里需要在shared_ptr构造时传入deleter,用来销毁持有的数组,而unique_ptr无需此操作,因为unique_ptr重载了unique_ptr(T[])

get_foo()方法为什么不直接返回this指针?

参考 ”为什么尽量不要使用裸指针初始化智能指针“。聪明的小伙伴,想想如果多次调用get_foo()会发生什么?

好了,今天二师兄的面试之旅到这里就结束了。感谢小伙伴的耐心阅读。如果您觉得还不错,请多多支持二师兄,拜谢~

关注我,带你21天“精通”C++!(狗头)

C++面试八股文:什么是智能指针?的更多相关文章

  1. 【校招面试 之 C/C++】第27题 C++ 智能指针(三)之 unique_ptr

    auto_ptr<string> p1(new string ("auto") : //#1 auto_ptr<string> p2; //#2 p2 = ...

  2. 【校招面试 之 C/C++】第26题 C++ 智能指针(二)之 share_ptr

    1.综述 shared_ptr 是一个标准的共享所有权的智能指针, 允许多个指针指向同一个对象. 定义在 memory 文件中(非memory.h), 命名空间为 std. shared_ptr 是为 ...

  3. 【校招面试 之 C/C++】第25题 C++ 智能指针(一)之 auto_ptr

    1.智能指针背后的设计思想 我们先来看一个简单的例子: void remodel(std::string & str) { std::string * ps = new std::string ...

  4. C++智能指针简单剖析

    导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑.C++面试过程中,很多面试官都喜欢问智能指针相关的问题 ...

  5. 自己动手实现智能指针auto_ptr

    面试的时候,我们经常会被问到如何自己动手实现智能指针auto_ptr.今天我就一边参考STL库中的源代码,一边将auto_ptr的实现敲一遍. auto_ptr归根到底是一个模版类,那么这个类要实现哪 ...

  6. 关于智能指针auto_ptr

    智能指针auto_ptr和shared_ptr也是面试中经常被问到的一个 感觉看auto_ptr的源码反而更加容易理解一些,因为源码的代码量并不大,而且比较容易理解. 本篇主要介绍auto_ptr 其 ...

  7. 【转】C++智能指针简单剖析

    原文链接:http://www.cnblogs.com/lanxuezaipiao/p/4132096.html 导读 最近在补看 <C++ Primer Plus>第六版,这的确是本好书 ...

  8. 【C++】智能指针简单剖析

    转自 http://www.cnblogs.com/lanxuezaipiao/p/4132096.html 导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中 ...

  9. [转]C++智能指针简单剖析

    C++智能指针简单剖析  https://www.cnblogs.com/lanxuezaipiao/p/4132096.html 导读 最近在补看<C++ Primer Plus>第六版 ...

  10. C/C++ 智能指针简单剖析

    导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑.C++面试过程中,很多面试官都喜欢问智能指针相关的问题 ...

随机推荐

  1. rocketmq-spring : 实战与源码解析一网打尽

    RocketMQ 是大家耳熟能详的消息队列,开源项目 rocketmq-spring 可以帮助开发者在 Spring Boot 项目中快速整合 RocketMQ. 这篇文章会介绍 Spring Boo ...

  2. 5.根据uid获取用户所有收货地址信息和设置默认地址

    1.总结:昨天主要是实现了根据uid获取该用户的所有收货地址以及设置默认地址:再对默认地址的实现里面让我认识到它的具体操作,首先我们根据aid查询收货地址 再根据收货地址查询到地址归属人的信息,判断u ...

  3. 逍遥自在学C语言 | 位运算符^的高级用法

    前言 在上一篇文章中,我们介绍了|运算符的高级用法,本篇文章,我们将介绍^ 运算符的一些高级用法. 一.人物简介 第一位闪亮登场,有请今后会一直教我们C语言的老师 -- 自在. 第二位上场的是和我们一 ...

  4. fio性能测试-环境搭建,功能介绍,测试讲解

    fio性能测试-环境搭建,功能介绍,测试讲解 Fio介绍:FIO(Flexible I/O Tester)是一个用于测试磁盘.文件系统.块设备和网络设备性能的工具.它可以模拟不同类型的I/O负载,包括 ...

  5. mysql数据库常见优化方法

    1,创建适当的索引(主键索引.唯一索引.普通索引.全文索引.空间索引). 2,对sql语句进行优化--->慢查询(explain). 3,使用分表技术(水平分表,垂直分表),分区技术. 4,读写 ...

  6. C盘爆满的解决方法,不用删除文件,使用分区助手无损增加内存

    一.分区助手傲梅科技 对于我们C盘内存不足的来说,老师推荐的yyds. 我的内存C盘历史最低是900多M,1.5G还是多的,经过我不断的删除文件,发现没什么用,电脑用久了C盘文件占内存自然就多了!!改 ...

  7. 深度学习基础5:交叉熵损失函数、MSE、CTC损失适用于字识别语音等序列问题、Balanced L1 Loss适用于目标检测

    深度学习基础5:交叉熵损失函数.MSE.CTC损失适用于字识别语音等序列问题.Balanced L1 Loss适用于目标检测 1.交叉熵损失函数 在物理学中,"熵"被用来表示热力学 ...

  8. node服务端

    一,node起服务+数据交互+中间件 什么是node express koa node是js在后端运行时的一个环境 express,koa是基于node的框架,快速构建web应用 前后端交互方式 1. ...

  9. 2020-08-18:介绍下MR过程?

    福哥答案2020-08-18:[来自[MapReduce执行过程及运行原理详解] 答案](https://www.panziye.com/bigdata/625.html)MapReduce执行的4个 ...

  10. 2022-09-24:以下go语言代码输出什么?A:1;B:3;C:13;D:7。 package main import ( “fmt“ “io/ioutil“ “net/

    2022-09-24:以下go语言代码输出什么?A:1:B:3:C:13:D:7. package main import ( "fmt" "io/ioutil" ...