某日二师兄参加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. 联想拯救者Y9000P 2023版 双系统ubuntu安装nvidia显卡驱动、cuda及cudnn简明教程

    前言 对于从事机器学习.深度学习.图像处理.自然语言处理等科研与工作的小伙伴们,ubuntu系统是一个不错的选择,本人前几天入手拯救者y9000p 2023版本,配置为:RTX4060 16G 13代 ...

  2. Barplot/pie/boxplot作图详解——R语言

    当数据以简单的可视化的形式呈现时,数据便更具有意义并且更容易理解,因为人眼很难从原始数据中得出重要的信息.因此,数据可视化成为了解读数据最重要的方式之一.条形图和箱线图是了解变量分布的最常用的图形工具 ...

  3. 二进制安装Kubernetes(k8s) v1.23.6

    二进制安装Kubernetes(k8s) v1.23.6 背景 kubernetes二进制安装 1.23.3 和 1.23.4 和 1.23.5 和 1.23.6 文档以及安装包已生成. 后续尽可能第 ...

  4. 3.2 构造器、this、包机制、访问修饰符、封装

    构造器 构造器:在实例化的一个对象的时候会给对象赋予初始值,因此我们可以通过修改构造器,来改变对象的初始值,构造器是完成对象的初始化,并不是创建对象 我们也可以创建多个构造器实现不同的初始化,即构造器 ...

  5. 3.1 JAVA方法:

    JAVA方法: 何为方法 方法是语句的集合,这个集合执行一个功能 方法包含于类或对象中 方法在程序中被创建,在其他地方被引用 java全是值传递 方法的定义和调用 方法的定义: 修饰符 返回类型 方法 ...

  6. Django框架——手写web框架、wsgiref模块、动静态网页、jinja2模块、主流web框架、Django简介、基本使用、app概念、目录结构、三板斧

    web应用 '''通过浏览器访问的应用程序!!!''' 1.两种模式c/s b/s B/S:browser---------------->server 2.web应用程序的有点 2.1 只需要 ...

  7. Nginx配置https并监听80端口重定向到443

    1.进入nginx安装目录,进入config文件夹编辑nginx.conf文件 vim nginx.conf 配置端口  443 listen 443 http2 ssl default_server ...

  8. 如何在Godot中使用ParallaxBackground实现稳定的2d游戏背景[一问随笔]

    问题: 我尝试给2d游戏添加静态的背景,当角色运动速度很快时相机的渲染就跟不上角色了,背景会发生这样巨大的位移. 我将Camera2d节点和背景节点绑在一起,但根本无法解决这个问题. 我还尝试制作天空 ...

  9. springboot升级过程中踩坑定位分析记录 | 京东云技术团队

    作者:京东零售 李文龙 1.背景 " 俗话说:为了修复一个小bug而引入了一个更大bug " 因所负责的系统使用的spring框架版本5.1.5.RELEASE在线上出过一个偶发的 ...

  10. 【解决方法】域控制器升级报错-Verification of prerequisites for Domain Controller promotion failed.......

    目录-快速跳转 问题描述 原因分析: 解决方案: 附言: 问题描述 在 VM 内 windows 2019 中域控制器安装完成后进行第一次设置进行Prerequisites Check(先决条件检查) ...