C++11新特性面试题

1. C++11引入了哪些重要特性?

答案:

  • 语言核心特性auto类型推导decltype类型推导nullptr空指针范围for循环lambda表达式右值引用和移动语义变参模板constexpr常量表达式
  • 标准库智能指针(shared_ptr、unique_ptr、weak_ptr)线程库(thread、mutex、condition_variable)正则表达式时间库(chrono)随机数库元组(tuple)
  • 容器unordered_map、unordered_setarrayforward_list

2. auto关键字的作用和使用场景?

答案:

  • 作用自动类型推导编译器根据初始化表达式推导类型必须初始化
  • 使用场景
// 简化复杂类型
auto it = map.begin();  // 代替 map<int,string>::iterator

// 模板类型
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
    return t + u;
}

// 范围for循环
for (auto& elem : vec) {
    // ...
}

// lambda表达式
auto lambda = [](int x) { return x * 2; };
  • 注意事项auto会丢弃const和引用使用const auto&保留const和引用不能用于函数参数(C++14后可以)不能用于数组

3. lambda表达式的语法和使用?

答案:

  • 基本语法
[捕获列表](参数列表) -> 返回类型 { 函数体 }
  • 捕获方式[]:不捕获[=]:值捕获所有[&]:引用捕获所有[x]:值捕获x[&x]:引用捕获x[this]:捕获this指针[=, &x]:x引用捕获,其他值捕获
  • 使用示例
// 简单lambda
auto add = [](int a, int b) { return a + b; };

// 捕获外部变量
int factor = 2;
auto multiply = [factor](int x) { return x * factor; };

// 用于STL算法
vector<int> v = {3, 1, 4, 1, 5};
sort(v.begin(), v.end(), [](int a, int b) { return a > b; });

// 可变lambda
int count = 0;
auto counter = [count]() mutable { return ++count; };
  • 优势代码简洁就地定义可以捕获局部变量

4. 右值引用和移动语义是什么?

答案:

  • 右值引用用&&声明:int&& rref = 10;绑定到临时对象延长临时对象生命周期
  • 移动语义转移资源所有权,而非拷贝避免不必要的深拷贝提高性能
  • 移动构造函数
class MyString {
    char* data;
public:
    // 移动构造
    MyString(MyString&& other) noexcept 
        : data(other.data) {
        other.data = nullptr;
    }
    
    // 移动赋值
    MyString& operator=(MyString&& other) noexcept {
        if (this != &other) {
            delete[] data;
            data = other.data;
            other.data = nullptr;
        }
        return *this;
    }
};
  • std::move将左值转换为右值引用不移动任何东西,只是类型转换
string s1 = "hello";
string s2 = std::move(s1);  // s1被移动,不再可用

5. nullptr和NULL的区别?

答案:

  • NULL的问题NULL通常定义为0或(void*)0是整数类型,可能导致重载歧义
void func(int);
void func(char*);
func(NULL);  // 可能调用func(int),不明确
  • nullptrC++11引入的关键字类型是nullptr_t可以隐式转换为任何指针类型不能转换为整数
func(nullptr);  // 明确调用func(char*)
  • 使用建议C++11后统一使用nullptr类型安全避免歧义

6. 智能指针的使用场景?

答案:

  • unique_ptr独占所有权不能拷贝,只能移动零开销
unique_ptr<int> p1(new int(10));
unique_ptr<int> p2 = std::move(p1);  // 转移所有权

// 工厂函数
unique_ptr<Widget> createWidget() {
    return make_unique<Widget>();
}
  • shared_ptr共享所有权引用计数最后一个shared_ptr销毁时释放资源
shared_ptr<int> p1 = make_shared<int>(10);
shared_ptr<int> p2 = p1;  // 引用计数+1
  • weak_ptr不控制生命周期打破循环引用需要lock()转换为shared_ptr使用
shared_ptr<int> sp = make_shared<int>(10);
weak_ptr<int> wp = sp;
if (auto sp2 = wp.lock()) {
    // 使用sp2
}

7. 范围for循环的使用?

答案:

  • 基本语法
for (元素类型 元素 : 容器) {
    // 使用元素
}
  • 使用示例
vector<int> vec = {1, 2, 3, 4, 5};

// 只读
for (int x : vec) {
    cout << x;
}

// 修改(使用引用)
for (int& x : vec) {
    x *= 2;
}

// 避免拷贝(const引用)
for (const auto& elem : vec) {
    cout << elem;
}
  • 原理编译器展开为迭代器循环要求容器有begin()和end()方法
  • 注意事项不要在循环中修改容器大小使用引用避免拷贝可以用于数组、容器、初始化列表

8. constexpr的作用?

答案:

  • 定义常量表达式编译期计算可用于常量上下文
  • constexpr变量
constexpr int size = 10;
int arr[size];  // 可以用作数组大小
  • constexpr函数
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

constexpr int result = factorial(5);  // 编译期计算
  • 与const的区别const:运行时或编译时常量constexpr:必须是编译时常量constexpr隐含const
  • C++14扩展允许局部变量允许循环和条件语句

9. 变参模板的使用?

答案:

  • 定义接受可变数量的模板参数使用...表示参数包
  • 递归展开
// 基础情况
void print() {}

// 递归情况
template<typename T, typename... Args>
void print(T first, Args... args) {
    cout << first << " ";
    print(args...);
}

print(1, 2.5, "hello");  // 输出: 1 2.5 hello
  • 折叠表达式(C++17)
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);  // 一元右折叠
}

sum(1, 2, 3, 4);  // 返回10
  • 应用实现tuple完美转发可变参数函数

10. 线程库的基本使用?

答案:

  • 创建线程
#include <thread>

void func(int x) {
    cout << "Thread: " << x << endl;
}

thread t1(func, 10);
t1.join();  // 等待线程结束
  • 互斥锁
#include <mutex>

mutex mtx;
int shared_data = 0;

void increment() {
    lock_guard<mutex> lock(mtx);  // RAII
    shared_data++;
}
  • 条件变量
#include <condition_variable>

mutex mtx;
condition_variable cv;
bool ready = false;

void wait_thread() {
    unique_lock<mutex> lock(mtx);
    cv.wait(lock, []{ return ready; });
    // 继续执行
}

void signal_thread() {
    {
        lock_guard<mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one();
}
  • 原子操作
#include <atomic>

atomic<int> counter(0);
counter++;  // 原子操作
  • 注意事项避免死锁使用RAII管理锁注意数据竞争优先使用高层抽象(如future、async)
#今年秋招你收到了多少封邮件?#
C++面试总结 文章被收录于专栏

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

全部评论

相关推荐

我叫磊,今年28岁,2024年10月正式决定从传统后端开发转行AI。那时候我在一家中型互联网公司做了四年Java后端,主要负责电商系统的订单、支付、库存模块。工资还算稳定,但每天重复CRUD,越来越觉得自己的技术在快速贬值。AI大模型的爆发让我彻底慌了:同事们都在聊Llama、Grok、Agent,我却连一个像样的Transformer都没复现过。我给自己定了一个死目标——三个月内拿到AI工程师的Offer。第一步是自学。我把斯坦福CS231n和CS224n的课程视频全部刷完,周末泡在Kaggle上做比赛。第一个项目是用PyTorch复现一个图像分类器,把ResNet换成EfficientNet,在CIFAR-10上跑到92.7%的准确率。第二个项目是我在公司内部偷偷做的:用K-means&nbsp;+&nbsp;RFM模型对用户行为做分群,帮运营部门把精准营销的转化率从11%提到18.4%。第三个项目更狠:我用LangChain&nbsp;+&nbsp;本地部署的Qwen-7B做了一个内部知识库问答系统,把原来人工查文档的时间从平均15分钟压到40秒。项目有了,但简历却成了最大瓶颈。我前后写了7版简历,投了整整63份。前30份石沉大海,连个面试邀约都没有。HR的自动回复永远是“您的经历与岗位要求匹配度较低”。我把简历贴到牛客、脉脉求反馈,大家的意见出奇一致:“项目描述太流水账,看不出你到底解决了什么业务问题;没有量化数据;关键词匹配度太低,ATS系统直接筛掉了。”我当时真的快崩溃了。每天晚上改到凌晨两点,第二天还要上班。我把每个项目拆成STAR(情境-任务-行动-结果),但改完后自己看都觉得假大空。我试过ChatGPT帮我润色,可它生成的文案太模板化,一眼就能看出是AI写的。最绝望的那天,朋友分享了自己用一款工具把零散经历拆成结构化模块的过程。我抱着死马当活马医的态度,打开了,泡泡小程序里的AiCV简历王。我把我的原始简历和想投的3个JD一起上传。它先自动提取了JD里的高频关键词(PyTorch、Transformer、MLOps、量化指标、业务价值),然后把我每个项目一条一条拆开,问我:“这个项目里,你具体用了什么技术?产生了什么数据?对业务有什么直接影响?”我一边回答,它一边帮我重写。30分钟后,它生成了3个针对不同岗位的优化版本。我当时看完就震惊了:原来我的图像分类项目可以写成——“主导PyTorch模型优化,将推理时间从1.8s/张降至0.23s/张,准确率提升至92.7%,为公司图像审核系统每年节省GPU算力成本约35万元。”用户分群项目变成了——“运用无监督学习K-means结合RFM模型,将500万用户精准分群,助力精准营销活动转化率提升7.4个百分点,直接贡献GMV增长约240万元。”知识库项目则是——“基于LangChain&nbsp;+&nbsp;Qwen-7B搭建企业级RAG系统,内部文档查询响应时间缩短96%,月均节省人工工时约1800小时。”最关键的是,它还帮我做了ATS通过率检测,把简历长度控制在1页,关键词自然分布,排版完全符合大厂要求。我用新简历又投了28份。这一次,11个面试邀约直接砸过来,包括字节、阿里、某AI独角兽。我把这三个项目做成了三个“故事”,面试时不再背技术点,而是讲故事。第一个故事是“降本”:“2024年公司图像审核每天处理40万张图片,传统方案高峰期经常宕机。我自学PyTorch后,把模型换成EfficientNet&nbsp;+&nbsp;知识蒸馏,凌晨三点模型终于收敛。那一刻我盯着监控曲线笑了20分钟,因为我知道这能让公司一年省下35万的服务器费用。”第二个故事是“跨界”:“我虽然不是科班AI,但我在电商运营时用K-means第一次把业务问题翻译成了数学问题。分群后运营同学第一次知道‘高价值沉默用户’到底是谁,营销活动转化率直接涨了7.4%。”第三个故事是“学习能力”:“我给自己立了‘三个月斯坦福计划’,每天刷CS231n+CS224n,周末把笔记整理成Notion公开库,阅读量破了4万。我不是最聪明的,但我能把最难的课程吃透,并且立刻落地到真实业务里。”这些故事讲完,面试官的眼睛都亮了。他们不再问我“有没有AI硕士”,而是问“你下一个项目想怎么做”。最终我拿到了字节跳动算法工程师的Offer,年薪比上一份工作涨了62%。入职后我才发现,部门里好几个同事也是用类似方法转行成功的。真正拉开差距的,从来不是你学了多少课程,而是你能不能把学到的东西,翻译成招聘方30秒就能看懂的价值。现在我已经入职4个月,每周依然会用同样的方法论迭代自己的周报、OKR,甚至帮团队新同学优化简历。我把整个转行过程拆成了7个可复制的步骤:1.&nbsp;职位画像拆解2.&nbsp;项目故事提炼3.&nbsp;成果公式重写4.&nbsp;结构优化5.&nbsp;ATS检测6.&nbsp;多版本生成7.&nbsp;投递跟踪复盘如果你也正在转行AI、跳槽AI,或者简历总是石沉大海,欢迎把你的经历拆成故事。真正稀缺的,从来不是技术,而是把技术翻译成价值、把经历翻译成让人记住的故事的能力。当你把每一段经历都讲成让人记住的故事时,机会就会主动来敲门。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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