bilibili C++开发 二面

1. 讲讲 C++ 的几种智能指针

答案:常见的有 unique_ptrshared_ptrweak_ptr,以及早期已经废弃的 auto_ptrunique_ptr 是独占所有权,同一时刻只能有一个指针拥有对象,不能拷贝,只能移动,适合表达“这个资源就归我管”。shared_ptr 是共享所有权,多个智能指针可以共同管理一个对象,底层通过控制块维护引用计数。weak_ptr 是对 shared_ptr 管理对象的弱观察者,它不增加强引用计数,主要解决循环引用以及“只想看一眼对象还在不在”的问题。如果面试官继续往下问,核心一般就会落到 shared_ptr/weak_ptr 的控制块、计数器、线程安全边界和 enable_shared_from_this 上。

代码:

#include <iostream>
#include <memory>
using namespace std;

int main() {
    unique_ptr<int> p1 = make_unique<int>(10);

    shared_ptr<int> p2 = make_shared<int>(20);
    shared_ptr<int> p3 = p2;

    weak_ptr<int> wp = p2;
    if (auto sp = wp.lock()) {
        cout << *sp << endl;
    }
    return 0;
}

2. shared_ptr 和 weak_ptr 是如何实现的

这两个智能指针的关键不在指针本身,而在背后的控制块。控制块里通常会放对象指针、强引用计数、弱引用计数、删除器、分配器等信息。shared_ptr 持有对象所有权,它拷贝时强引用计数加一,析构时强引用计数减一;当强引用计数降到零,对象本体会被释放。weak_ptr 不拥有对象,它只是共享同一个控制块,拷贝和析构时只影响弱引用计数,不影响对象生命周期。当强引用计数已经归零但弱引用计数还没归零时,对象本体虽然销毁了,但控制块不能立刻释放,因为还可能有人通过 weak_ptr 查询对象状态。只有当强弱计数都归零,整个控制块才会被销毁。

3. 强引用计数和弱引用计数分别是什么

强引用计数表示“当前有多少个共享所有权的持有者”,也就是有多少个 shared_ptr 在管理这个对象。只要强引用计数大于零,对象就必须活着。弱引用计数表示“当前还有多少个弱观察者或者控制块附加关系在使用这份控制信息”,也就是 weak_ptr 以及类似 enable_shared_from_this 内部维护的那份弱引用。对象是否销毁,看的是强引用计数;控制块是否销毁,要看强弱计数是否都归零。这个区分非常重要,因为 weak_ptr 的存在本质上就是想让“对象生命周期”和“控制块生命周期”分离。

4. 为什么要有弱引用计数

如果只有强引用计数,那么对象一旦析构,控制块也会被一起销毁。这样所有弱引用就没地方判断对象是否已经过期,也没法安全地执行 lock()。所以弱引用计数存在的意义,就是让控制块可以比对象活得更久一点。这样即使对象已经没了,weak_ptr 仍然能通过控制块知道“对象已经失效”,而不是访问野内存。另一个非常典型的作用就是解决循环引用。两个对象如果都用 shared_ptr 相互指向,强引用计数永远降不到零;其中一端改成 weak_ptr,这个环就断开了。

代码:

#include <iostream>
#include <memory>
using namespace std;

struct B;

struct A {
    shared_ptr<B> b;
    ~A() { cout << "A destroyed\n"; }
};

struct B {
    weak_ptr<A> a; // 打破循环引用
    ~B() { cout << "B destroyed\n"; }
};

int main() {
    auto pa = make_shared<A>();
    auto pb = make_shared<B>();
    pa->b = pb;
    pb->a = pa;
    return 0;
}

5. enable_shared_from_this 了解吗,讲一讲

enable_shared_from_this<T> 的作用,是让对象内部能够安全地拿到“指向自己”的 shared_ptr。如果一个对象本来已经被某个 shared_ptr 管理了,这时候在对象内部如果直接写 shared_ptr<T>(this),就会额外创建一个新的控制块,最终会导致重复释放。enable_shared_from_this 解决的就是这个问题。它让对象内部保存一份指向同一控制块的弱引用,然后通过 shared_from_this() 从这份弱引用构造出新的 shared_ptr,这样得到的新指针和外面的 shared_ptr 共享同一个控制块。它本质上不是“让对象变成智能指针”,而是“让对象能安全地接入已经存在的那份共享所有权体系”。

代码:

#include <iostream>
#include <memory>
using namespace std;

class Node : public enable_shared_from_this<Node> {
public:
    shared_ptr<Node> getSelf() {
        return shared_from_this();
    }
};

int main() {
    auto p = make_shared<Node>();
    auto self = p->getSelf();
    cout << p.use_count() << endl; // 2
    return 0;
}

6. enable_shared_from_this 是怎么实现的

它的核心思路就是在基类内部维护一个指向当前对象控制块的 weak_ptr<T>。当某个对象第一次被 shared_ptr 接管时,标准库会检测它是否继承了 enable_shared_from_this,如果继承了,就把这个内部弱引用绑定到当前这份控制块上。之后对象内部调用 shared_from_this(),其实就是对这份内部 weak_ptr 执行一次 lock() 或等价构造,返回一个新的 shared_ptr,但共享的是原来的控制块,不会新建控制块。所以你面试里答“weak_ptr + 弱引用计数”这个方

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++ 常考面试题总结 文章被收录于专栏

本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

全部评论

相关推荐

点赞 评论 收藏
分享
03-12 21:07
门头沟学院 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务