首页 > 编程语言 >C++面试八股文:什么是智能指针?

C++面试八股文:什么是智能指针?

时间:2023-06-26 23:47:40浏览次数:43  
标签:std 面试官 八股文 C++ 智能 shared ptr 指针

C++面试八股文:什么是智能指针?

某日二师兄参加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()会发生什么?

标签:std,面试官,八股文,C++,智能,shared,ptr,指针
From: https://www.cnblogs.com/bujidao1128/p/17507457.html

相关文章

  • C++ Primer 第一章 开始
    输入输出C++并未定义任何输入输出,取而代之包含了一个标准库提供输入输出。iostream库包含两个基础类型:istream和ostream,分别表示输入流和输出流,流代表字符序列。标准库定义了4个IO对象cin为istream类型对象,也称为标准输入cout为ostream类型对象,也称为标准输出标准库还定义了......
  • C++面试八股文:std::deque用过吗?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第26面:面试官:deque用过吗?二师兄:说实话,很少用,基本没用过。面试官:为什么?二师兄:因为使用它的场景很少,大部分需要性能、且需要自动扩容的时候使用vector,需要随机插入和删除的时候可以使用list。面试官:那你知道STL中的stack是如何实......
  • C++指针函数
    指针函数指针函数有些像C#中的委托delegate(不知道理解的对不对)。定义函数指针int*compare(int,int);一般简写为typedefint(*compare)(int,int);这样就定义了一个名为compare的函数指针。compare指针类型为:指向返回int类型并带有两个int参数的函数的指针。函数指......
  • C++ 指针形参与引用参数
    指针形参与引用参数指针形参指针作形参时,若在函数中修改指针对象的值,则对应实参的值会对应修改。#include<iostream>usingnamespacestd;voidChange(int*p){*p=400;};intmain(intargc,charconst*argv[]){intvalue=1;int*argsPiont=&va......
  • C++11特性简单介绍
    自动类型推导autoautox=10;//推导x为int类型autostr="Hello";//推导str为constchar*类型基于范围的For循环for(int&i:someDataStructure){doSomething();}for(inti:someDataStructure)doSomething();在上面的两个for循环中,第一个使用引用,第二个启用按......
  • 学习C++就这么简单 ——《写给大家看的C++书》
    C++已经有很多年的历史了,虽然在它之后又出现了Java和C#之类的新语言,但它至今仍是人们开发软件时的最佳选择之一。那些巨头中的巨头,如微软、Adobe、英特尔、亚马逊、Google、苹果、诺基亚等公司,都在使用C++。这门语言相对比较容易使用(选用本书作为入门教材就更是如此了......
  • C/C++航空客运订票系统[2023-06-26]
    C/C++航空客运订票系统[2023-06-26]实验1航空客运订票系统问题描述:航空客运订票的业务活动包括查询航线和客票预订的信息、客票预订和办理退票等,设计一个程序使上述任务借助计算机来完成。基本要求:(一)系统必须存储的数据信息。1.信息:飞机抵达的城市、航班号、飞机号、起降......
  • C++一读一写无锁队列
    //一读一写的无锁管道队列template<classT>classPipelineList{private:template<classT>structqnode{structqnode*next;Tdata;};structqnode<T>*volatilem_front;structqnode<T>*volatilem_......
  • c++ std::execution::par,std::execution::par_unseq
    #include<algorithm>#include<chrono>#include<cstdint>#include<execution>#include<iostream>#include<random>#include<vector>std::random_devicerd;std::mt19937_64mt{rd()};template<typenameT>......
  • 为什么 Keil 中C/C++选项要 define STM32F10X_LD/MD/HD
    原因1:配置相应的中断向量表 原因2:配置相应的寄存器  总结原因:因为所有的stm32f10x 系列的芯片都会用到stm32f10x.h 这个头文件,但是问题的所在是:每种芯片的配置不同(中断向量个数、寄存器个数等等)因此宏条件编译#if!defined 判断这个宏(这个宏就是STM32F10X_LD......