影石 音视频开发-C++ 一面

1. 自我介绍

2. 写一个高性能模块,需要用链表时,会优先考虑 std::list

答案:不一定。很多人看到“频繁插入删除”就先想到 std::list,但高性能场景下不能只看时间复杂度,还得看缓存局部性、内存分配次数、节点额外开销、遍历成本。std::list 的确能做到已知位置 O(1) 插入删除,但它不是连续内存,每个节点单独分配,cache 命中率通常比较差,实际性能未必比 vectordeque 好。如果模块里遍历远多于插删,或者数据量大、对 cache 敏感,往往连续存储更占优势。如果确实要频繁中间插删,又担心节点分配成本,工程里还可能结合对象池、侵入式链表或者 boost::intrusive 一类方案。所以这题本质不是“链表快不快”,而是选容器要结合访问模式和硬件友好性来看。

3. 如何避免内存泄漏

答案:核心思路不是“记得 delete”,而是让资源生命周期可控。比较稳的方式一般有三种:第一是用 RAII,把资源获取和释放绑到对象生命周期上;第二是优先使用标准容器和智能指针,减少裸指针直接管理资源;第三是明确所有权边界,谁申请谁释放,或者由唯一拥有者负责释放。另外在工程里还要结合工具去兜底,比如 ASan、Valgrind、Visual Leak Detector、自定义内存统计,这样不仅能预防,还能尽快发现问题。

4. newdelete 的规范使用

答案:newdelete 必须成对出现,new[]delete[] 也必须成对出现,不能混用。new 做了两件事,一是分配内存,二是调用构造函数;delete 也是两步,先调用析构函数,再释放内存。如果对象是通过基类指针释放,而且类存在继承层次,那基类析构函数通常要是虚函数。工程里更推荐“少直接用 new/delete”,尽量交给容器、智能指针和工厂函数管理,否则资源路径一复杂,很容易漏掉释放点。

代码:

#include <iostream>
using namespace std;

class A {
public:
    A() { cout << "ctor\n"; }
    ~A() { cout << "dtor\n"; }
};

int main() {
    A* p1 = new A;
    delete p1;

    A* p2 = new A[3];
    delete[] p2;
    return 0;
}

5. RAII 思想怎么理解

答案:RAII 可以理解成“资源获取即初始化”,对象构造时拿到资源,对象析构时自动释放资源。它的价值在于把资源管理从“依赖人记得释放”变成“依赖语言对象生命周期自动释放”。这样即使函数中途 return,或者抛异常,也能保证资源被正确清理。RAII 不只是管理内存,还适用于文件句柄、锁、socket、数据库连接这些资源。像 lock_guardunique_ptrfstream,本质上都是 RAII 的体现。

代码:

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

mutex mtx;

void func() {
    lock_guard<mutex> lock(mtx);
    cout << "critical section\n";
}

6. 如果让你手写一个智能指针,最核心要考虑什么

答案:这题如果从文件管理切到内存释放,本质没变,考的还是资源托管设计。最核心要考虑的是所有权模型、析构时机、拷贝语义、移动语义和异常安全。如果是独占型智能指针,那要禁止拷贝、支持移动;如果是共享型智能指针,就要维护引用计数,还要考虑线程安全和循环引用问题。另外删除器也很关键,因为对象不一定总是 delete,有时候可能是 delete[]fclose 或者自定义释放逻辑。真正写的时候,很多细节都在“边界条件”上,比如自赋值、空指针、控制块释放时机、对象和控制块是否分离。

代码:

#include <iostream>
using namespace std;

template <typename T>
class UniquePtr {
public:
    explicit UniquePtr(T* p = nullptr) : ptr_(p) {}
    ~UniquePtr() { delete ptr_; }

    UniquePtr(const UniquePtr&) = delete;
    UniquePtr& operator=(const UniquePtr&) = delete;

    UniquePtr(UniquePtr&& other) noexcept : ptr_(other.ptr_) {
        other.ptr_ = nullptr;
    }

    UniquePtr& operator=(UniquePtr&& other) noexcept {
        if (this != &other) {
            delete ptr_;
            ptr_ = other.ptr_;
            other.ptr_ = nullptr;
        }
        return *this;
    }

    T* operato

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

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

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

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

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