C++面试八股文:什么是智能指针?
某日二师兄参加XXX科技公司的C++工程师开发岗位第19面:
面试官:什么是智能指针?
二师兄:智能指针是C++11引入的类模板,用于管理资源,行为类似于指针,但不需要手动申请、释放资源,所以称为智能指针。
面试官:C++11引入了哪些智能指针?
二师兄:三种,分别是
shared_ptr
、unique_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_ptr
和unique_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_ptr
和unique_ptr
有什么不同吗?
这里需要在shared_ptr
构造时传入deleter
,用来销毁持有的数组,而unique_ptr
无需此操作,因为unique_ptr
重载了unique_ptr(T[])
。
get_foo()
方法为什么不直接返回this
指针?
参考 ”为什么尽量不要使用裸指针初始化智能指针“。聪明的小伙伴,想想如果多次调用get_foo()
会发生什么?
好了,今天二师兄的面试之旅到这里就结束了。感谢小伙伴的耐心阅读。如果您觉得还不错,请多多支持二师兄,拜谢~
关注我,带你21天“精通”C++!(狗头)
C++面试八股文:什么是智能指针?的更多相关文章
- 【校招面试 之 C/C++】第27题 C++ 智能指针(三)之 unique_ptr
auto_ptr<string> p1(new string ("auto") : //#1 auto_ptr<string> p2; //#2 p2 = ...
- 【校招面试 之 C/C++】第26题 C++ 智能指针(二)之 share_ptr
1.综述 shared_ptr 是一个标准的共享所有权的智能指针, 允许多个指针指向同一个对象. 定义在 memory 文件中(非memory.h), 命名空间为 std. shared_ptr 是为 ...
- 【校招面试 之 C/C++】第25题 C++ 智能指针(一)之 auto_ptr
1.智能指针背后的设计思想 我们先来看一个简单的例子: void remodel(std::string & str) { std::string * ps = new std::string ...
- C++智能指针简单剖析
导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑.C++面试过程中,很多面试官都喜欢问智能指针相关的问题 ...
- 自己动手实现智能指针auto_ptr
面试的时候,我们经常会被问到如何自己动手实现智能指针auto_ptr.今天我就一边参考STL库中的源代码,一边将auto_ptr的实现敲一遍. auto_ptr归根到底是一个模版类,那么这个类要实现哪 ...
- 关于智能指针auto_ptr
智能指针auto_ptr和shared_ptr也是面试中经常被问到的一个 感觉看auto_ptr的源码反而更加容易理解一些,因为源码的代码量并不大,而且比较容易理解. 本篇主要介绍auto_ptr 其 ...
- 【转】C++智能指针简单剖析
原文链接:http://www.cnblogs.com/lanxuezaipiao/p/4132096.html 导读 最近在补看 <C++ Primer Plus>第六版,这的确是本好书 ...
- 【C++】智能指针简单剖析
转自 http://www.cnblogs.com/lanxuezaipiao/p/4132096.html 导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中 ...
- [转]C++智能指针简单剖析
C++智能指针简单剖析 https://www.cnblogs.com/lanxuezaipiao/p/4132096.html 导读 最近在补看<C++ Primer Plus>第六版 ...
- C/C++ 智能指针简单剖析
导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑.C++面试过程中,很多面试官都喜欢问智能指针相关的问题 ...
随机推荐
- 中英文拼写检测纠正开源项目使用入门 word-checker 1.1.0
项目简介 word-checker 本项目用于单词拼写检查.支持英文单词拼写检测,和中文拼写检测. 特性说明 可以迅速判断当前单词是否拼写错误 可以返回最佳匹配结果 可以返回纠正匹配列表,支持指定返回 ...
- 随机服务系统模拟—R实现(一)
排队论--随机服务系统 日常生活中存在大量有形和无形的排队或拥挤现象,如旅客购票排队,市内电话占线等现象.排队论的基本思想是 1909 年丹麦数学家.科学家,工程师 A. K. 埃尔朗在解决自动电话设 ...
- 更新pip遇到的问题及解决方法
问题ython -m pip install --upgrade pip --user D:\APP\Anaconda3\python.exe: No module named pip解决方法 pyt ...
- 四月十七日Java基础知识点
1.默认构造方法:如果class前面有public修饰符,则默认的构造方法也会是public的.由于系统提供的默认构造方法往往不能满足需求,所以用户可以自己定义类的构造方法来满足需要,一旦用户为该类定 ...
- day05 运算符和流程控制
Day05 逻辑运算符 成员运算符 身份运算符 流程控制(重点) if判断 while循环 标志位的使用 逻辑运算符 and 与 #可以用and链接多个条件,会按照从左到右的顺序依次判断,有一个为F ...
- Redis读书笔记(三)
单机数据库的实现 Redis数据库 Redis数据库的实现 struct redisServer { //... //保存服务器中的所有数据库, 数组 redisDB *db; //服务器的数据库数量 ...
- 【c#表达式树】最完善的表达式树Expression.Dynamic的玩法
引言 在我第一次写博客的时候,写的第一篇文章,就是关于表达式树的,链接:https://www.cnblogs.com/1996-Chinese-Chen/p/14987967.html,其中,当时一 ...
- mysql迁移:mysqldump导出数据库
问题描述:要将一个mysql中六个数据库导出来,使用mysqldump导出 mysqldump使用语法:mysqldump -uroot -p -S /data/mysql/db_itax_m/mys ...
- laravel 中使用的 PDF 扩展包 laravel-dompdf 和 laravel-snappy
这两天项目中需要将HTML页面转换为PDF文件方便打印,我在网上搜了很多资料.先后尝试了laravel-dompdf和laravel-snappy两种扩展包,个人感觉laravel-snappy比较好 ...
- 用 Gaussian Process 建模 state-action 空间相关性,加速 Multi-Fidelity RL
目录 全文快读 1 intro 3 背景 4 method 4.1 model-based 算法:GP-VI-MFRL 4.2 model-free 算法:GPQ-MFRL 5 experiment ...