五、C++新特性、关键字与编译原理(共25项)
1.C/C++中宏定义的相关知识
2.C/C++中typedef关键字的相关知识
3.介绍一下register关键字
4.介绍一下const关键字
5.介绍一下external关键字
6.介绍一下volatile关键字
7.介绍一下dynamic在什么时候使用
8.#include<file.h> 与 #include "file.h"的区别?
9.const和#define有什么区别?
10.介绍一下static关键字的作用
11.完成字符串拷贝可以使用 sprintf、strcpy及 memcpy函数,请问这些函数有什么区别。
12.C++11的新特性都有哪些?
13.sizeof与strlen的区别?
14.C++17/20/23中哪些特性在AI工程中高频使用?
15.STL容器在AI数据处理和推理服务中如何选择?
16.std::string_view、std::span、std::optional在高性能接口中有什么价值?
17.为什么RAII是C++资源管理的核心思想?
18.在C++程序中调用被C编译器编译后的函数,为什么要加extern "C"?
19.CMake、ABI兼容和依赖管理在AI SDK交付中为什么重要?
20.C++中异常处理机制
21.什么时候用static
22.头文件中的#ifndef/define/endif有什么作用?
23.内联函数在编译时是做参数类型检查?
24.C++移动语义和完美转发如何减少AI数据拷贝?
25.C++模板、CRTP和类型擦除如何用于高性能框架?
结论先行
这25项围绕三条主线:
- 关键字/预编译 :宏、
const、static、extern、volatile等控制编译与链接行为; - C++现代特性 :C++11/17/20/23 的移动语义、智能指针、
string_view/span/optional、模板/CRTP/类型擦除提升性能与类型安全; - AI工程落地:RAII 管理资源、CMake/ABI 兼容保障 SDK 交付、移动语义减少张量/数据拷贝 ⚙️
一、预处理与关键字
1. 宏定义
文本替换,无类型检查。
#define PI 3.14
#define MAX(a,b) ((a)>(b)?(a):(b))
缺点:无作用域、无类型安全、调试困难。现代 C++ 优先用 const、inline、constexpr、template 替代。
2. typedef
给类型起别名。
typedef unsigned int uint;
typedef std::vector<int> IntVec;
C++11 后更推荐 using:
using uint = unsigned int;
3. register
建议编译器把变量放入寄存器。
C++11 起已废弃,编译器优化通常比人工指定更好。
4. const
表示只读,编译期常量或运行期常量。
const int a = 10;
void foo(const std::string& s); // 避免拷贝
增强可读性、安全性,支持编译期优化。
5. extern
声明外部定义的全局变量/函数,用于跨文件共享。
// a.cpp
int g_count = 0;
// b.cpp
extern int g_count;
6. volatile
告诉编译器不要优化该变量,每次从内存读取。
用于硬件寄存器、多线程中被其他线程修改的变量。
但不保证原子性和内存序,多线程同步请用
std::atomic。
7. dynamic 什么时候使用?
应指 dynamic_cast:用于多态类型间安全向下转型。
Base* p = new Derived();
Derived* d = dynamic_cast<Derived*>(p); // 失败返回 nullptr
运行时检查,有开销,只用于含虚函数的类。
8. #include <file.h> vs #include "file.h"
< >:从系统/标准库路径查找;" ":先从当前项目路径查找,再查系统路径。
9. const vs #define
const |
#define |
|---|---|
| 有类型、作用域、可调试 | 文本替换,无类型 |
| 编译器可优化 | 预处理替换 |
| 现代 C++ 推荐 | 尽量少用 |
10. static 关键字作用
三种场景:
- 局部静态变量:延长生命周期至程序结束;
- 文件内静态变量/函数:限制链接域,仅当前文件可见;
- 类静态成员:类级别共享。
11. sprintf/strcpy/memcpy 区别
| 函数 | 功能 | 安全性 |
|---|---|---|
strcpy |
字符串拷贝,遇 \0 停止 |
无边界检查,易溢出 |
memcpy |
按字节拷贝固定长度 | 不处理重叠,需保证不越界 |
sprintf |
格式化输出到字符串 | 无边界检查,极易溢出 |
现代 C++ 推荐
std::string、std::snprintf、std::copy。
13. sizeof vs strlen
-
sizeof:编译期运算符,返回类型/对象占用的字节数,含\0。 -
strlen:运行时函数,返回 C 字符串有效长度,不含\0。char s[] = "abc";
sizeof(s); // 4
strlen(s); // 3
18. 调用 C 编译后的函数为何要 extern "C"
C++ 编译器会对函数名做名字修饰(name mangling) ,C 编译器不会。
extern "C" 告诉 C++ 编译器按 C 规则链接,确保能找到 C 库中的符号。
extern "C" {
#include "c_lib.h"
}
21. 什么时候用 static
- 需要限制全局变量/函数作用域到当前文件;
- 函数内需要保持状态的变量;
- 类成员需要类级共享。
22. 头文件 #ifndef/#define/#endif 作用
防止头文件被多次包含,避免重复定义。
现代也常用 #pragma once(更简洁,但非标准)。
23. 内联函数在编译时做参数类型检查?
是的。内联函数是真正的函数 ,编译器会做类型检查、作用域检查,并可能将函数体直接展开到调用处。
宏则只做文本替换,无类型检查。
二、C++ 新特性
12. C++11 新特性
核心亮点:
auto/decltype- 范围 for 循环
- 右值引用与移动语义
std::unique_ptr/shared_ptr/weak_ptrnullptrconstexpr- Lambda 表达式
- 并发库(
thread、mutex、future) - 初始化列表、委托构造、默认/删除函数(
= default/= delete) std::array、std::tuple、std::unordered_map等
14. C++17/20/23 在 AI 工程中的高频特性
| 标准 | 特性 | AI 场景 |
|---|---|---|
| C++17 | std::string_view |
避免字符串拷贝,模型配置名、算子名 |
| C++17 | std::optional |
可选返回值,错误处理优雅 |
| C++17 | if constexpr |
编译期分支,模板框架 |
| C++17 | 结构化绑定 | 多返回值解包 |
| C++20 | std::span |
张量切片、缓冲区视图 |
| C++20 | Concepts | 模板约束,提升报错可读性 |
| C++20 | Modules | 替代头文件,加速编译 |
| C++20 | Coroutines | 异步推理、流式响应 |
| C++23 | std::expected |
显式错误处理 |
三、AI 工程实践
15. STL 容器在 AI 数据处理和推理服务中如何选择
- 连续内存 + 随机访问 →
std::vector(张量数据、batch) - 频繁插入删除中间元素 →
std::list(较少用) - 索引/缓存 →
std::unordered_map - 有序配置/日志 →
std::map - 避免拷贝的大缓冲区 →
std::span或std::string_view
16. string_view / span / optional 在高性能接口中的价值
string_view:只读字符串视图,零拷贝传参;span:连续内存视图,安全替代裸指针+长度;optional:显式表达"可能无值",替代魔术值或裸指针,降低空指针风险。
17. 为什么 RAII 是资源管理核心思想
RAII:资源获取即初始化。
对象构造时获取资源,析构时自动释放。
结合智能指针,能自动管理内存、文件、锁、网络句柄,避免泄漏和异常路径遗漏。
19. CMake、ABI 兼容和依赖管理在 AI SDK 交付中为什么重要
- CMake:跨平台构建,统一编译规则;
- ABI 兼容:编译器版本、标准库、编译选项不一致会导致链接/运行时崩溃,SDK 交付必须保证 ABI 一致;
- 依赖管理:OpenCV、CUDA、ONNX Runtime 等依赖复杂,需明确版本和传递依赖,避免"在我机器上能跑"。
20. C++ 异常处理机制
try {
throw std::runtime_error("error");
} catch (const std::exception& e) {
// 处理
}
异常会沿调用栈展开,自动调用局部对象的析构函数(栈展开)。
AI 服务中通常建议:核心推理路径少用异常,用 std::optional/std::expected/错误码保证性能可预测。
24. 移动语义和完美转发如何减少 AI 数据拷贝
- 移动语义 :将资源所有权转移,而不是深拷贝。例如大 tensor 从预处理传到推理引擎时用
std::move。 - 完美转发 :
std::forward保持参数的左右值属性,避免临时对象不必要的拷贝。
两者结合能显著降低大模型输入输出、中间特征图的内存拷贝开销 🚀
25. 模板、CRTP 和类型擦除如何用于高性能框架
- 模板:编译期多态,零运行时开销,用于泛型算子、张量类型。
- CRTP(奇异递归模板模式):静态多态,避免虚函数开销,实现编译期接口约束。
- 类型擦除 :运行时统一接口,例如
std::function、any,用于插件系统中隐藏具体类型。
模板 + CRTP 适合热路径高性能;类型擦除适合需要运行时多态的插件边界。
整体联系
这25项勾勒出一条从源码编译 到现代 C++ 特性 再到AI 工程落地的链路:
宏/关键字/头文件
编译链接
C++11/17/20/23 新特性
RAII/智能指针/移动语义
高性能接口 string_view/span/optional
模板/CRTP/类型擦除框架设计
CMake/ABI/SKD 交付
掌握这些,才能写出既现代、又能在 AI 推理框架和 SDK 中稳定交付的 C++ 代码 💪