Linux C++知识梳理

1. C++ 基础​

1.1 指针和引用的区别​

  • 区别:
特性 指针(T* 引用(T&
本质 变量,存储地址 别名(原变量的另一个名字)
初始化 可不初始化(但危险) 必须初始化,且绑定后不可变
可空性 可为 nullptr 不能为 null,必须绑定有效对象
重新赋值 可指向不同对象 不能重新绑定(始终指向初始化时的对象)
取地址 &ptr 是指针变量的地址 &ref 是被引用对象的地址
sizeof 通常是 8 字节(64 位系统) 等于被引用对象的大小
多级 支持(int**, int*** 不支持(无"引用的引用")
算术运算 支持(ptr++, ptr + n 不支持
  • 使用建议:
场景 推荐
需要可选/可空语义 指针(如 std::optional 出现前)
函数参数修改原值 引用(更安全、简洁)
实现数据结构(链表、树) 指针(需动态指向)
避免拷贝大对象 const 引用(const T&
与 C API 交互 指针(C 无引用)

选择原则:优先用引用,必要时用指针。

1.2 函数重载和运算符重载

特性 函数重载 运算符重载
目的 提供同名但参数不同的多个函数 为自定义类型赋予运算符语义(如 a + b
名称 任意合法函数名(如 print, add 固定为 operator@(如 operator+, operator[]
参数数量 任意(包括 0) 受运算符本身限制: • 一元运算符:1 个参数 • 二元运算符:2 个参数(成员函数时隐含 this
可重载的符号 无限制(自定义名) 仅限 C++ 内置运算符(不能创建新运算符,如 **
返回类型 可不同(但不能仅靠返回类型区分重载) 通常需符合直觉(如 + 返回新对象,= 返回引用)
调用方式 显式函数调用:func(a, b) 自然表达式:a + b 或显式:a.operator+(b)
必须为成员函数? 否(可全局或成员) 部分运算符必须为成员: • 赋值 = • 下标 [] • 函数调用 () • 成员访问 ->

1.3 虚函数和纯虚函数

特性 虚函数(Virtual Function) 纯虚函数(Pure Virtual Function)
定义方式 virtual 返回类型 func(参数); virtual 返回类型 func(参数) = 0;
是否必须实现 ✅ 必须提供实现(可在基类或派生类) ❌ 基类中无实现(= 0 表示"纯")
能否实例化基类 ✅ 可以(基类是具体类) ❌ 不能(基类成为抽象类)
目的 允许派生类可选重写,提供默认行为 强制派生类必须重写,定义接口契约
类的性质 普通类(concrete class) 抽象类(abstract class)
典型用途 提供可扩展的默认实现 定义接口(Interface)

1.4 拷贝构造函数与移动构造函数

特性 拷贝构造函数(Copy Constructor) 移动构造函数(Move Constructor)
定义形式 T(const T& other) T(T&& other)
参数类型 左值引用(const T& 右值引用(T&&
语义 深拷贝:创建新对象,原对象不变 资源转移:窃取原对象资源,原对象变为空/有效但未指定状态
触发时机 用已命名对象初始化新对象 (如 T a = b; 用临时对象/右值初始化新对象 (如 T a = func();
性能 可能昂贵(如复制大数组、文件) 通常廉价(仅指针交换)
是否修改源对象 ❌ 不修改 ✅ 修改(置为"空"状态)
默认生成条件 若未定义,编译器自动生成(成员逐个拷贝) 若未定义且满足条件,C++11+ 编译器自动生成

2. 内存管理

2.1 C++ 内存分区​

分区 别名 存储内容 生命周期 分配方式 特点
栈(Stack) 自动存储区 局部变量、函数参数、返回地址 函数作用域内 编译器自动分配/释放 快速、连续、大小有限(通常几 MB)
堆(Heap) 自由存储区 动态分配的对象(new/malloc 手动控制(直到 delete/free 程序员显式分配/释放 大小受限于虚拟内存,速度较慢,易内存泄漏
全局/静态区(Global/Static) 静态存储区 全局变量、静态变量(static)、常量字符串 整个程序运行期 编译时分配,启动时初始化 初始化一次,程序结束时释放
常量区(Constant / Literal) 字符串常量区 字符串字面量(如 "hello")、const 全局变量 程序运行期 编译时分配 只读,修改会导致未定义行为(如段错误)
代码区(Text / Code Segment) 程序区 可执行机器指令(函数体代码) 程序运行期 编译时生成 只读,通常与常量区合并或相邻

2.2 智能指针的种类及区别

特性 std::unique_ptr std::shared_ptr std::weak_ptr
所有权模型 独占所有权(唯一拥有者) 共享所有权(多个拥有者) 无所有权(观察者)
是否可复制 ❌ 不可复制(可移动) ✅ 可复制(引用计数 +1) ✅ 可复制
线程安全 本身非线程安全(但单线程下安全) 控制块线程安全(引用计数原子操作) shared_ptr
内存开销 无额外开销(≈ 原生指针) 额外控制块(引用计数 + deleter 等) shared_ptr 共享控制块
典型用途 替代 new/delete,RAII 资源管理 多个对象共享同一资源 解决 shared_ptr 的循环引用问题
删除器支持 ✅ 支持自定义删除器(模板参数) ✅ 支持自定义删除器(运行时存储) 依赖关联的 shared_ptr
转换关系 可转为 shared_ptr 可构造 weak_ptr 只能从 shared_ptr 构造

3. Linux 系统知识

3.1 进程与线程的区别​

对比维度 进程(Process) 线程(Thread)
资源占用 拥有独立的地址空间(代码段、数据段、堆、栈)、文件描述符表、信号处理表等,资源占用多。 共享所属进程的地址空间、文件描述符表等资源,仅拥有独立的栈、程序计数器(PC)、寄存器集合,资源占用少。
调度开销 进程切换时需保存和恢复整个地址空间、寄存器等上下文,开销大(毫秒级)。 线程切换仅需保存和恢复栈、PC、寄存器,开销小(微秒级),调度更高效。
通信方式 需通过进程间通信(IPC)机制,如管道(pipe)、消息队列(message queue)、共享内存(shared memory)、信号量(semaphore)等,实现复杂,效率较低。 可直接访问共享内存(进程地址空间中的全局变量、静态变量),通信简单高效;也可使用线程同步机制(互斥锁、条件变量)避免竞争。
独立性 进程间相互独立,一个进程崩溃通常不会影响其他进程(除非通过共享资源间接影响)。 线程属于同一进程,一个线程崩溃可能导致整个进程崩溃(如内存越界、野指针访问)。
PID 与 TID 每个进程有唯一的 PID(进程 ID),由内核分配。 每个线程有唯一的 TID(线程 ID),同一进程内的线程 PID 相同,TID 不同(Linux 下线程本质是轻量级进程,LWP)。

3.2 进程通信

IPC 方式 是否支持跨主机 数据流向 同步/异步 持久性 典型用途 优点 缺点
管道(Pipe) ❌ 仅限父子/相关进程 单向(匿名)或双向(命名) 阻塞(默认) 匿名:临时 命名:文件系统存在 简单父子进程通信 简单、内核支持 匿名 pipe 仅限亲缘进程;缓冲区有限
FIFO(命名管道) ❌ 本地 单向 阻塞 是(文件系统路径) 无关进程通信 可用于无亲缘关系进程 仍为单向,需额外同步
消息队列(Message Queue) ❌ 本地 双向(多对多) 可配置 是(内核持久) 结构化数据传递 消息边界清晰、支持优先级 内核限制消息大小/数量
共享内存(Shared Memory) ❌ 本地 双向(直接读写) 异步 是(需显式删除) 高性能大数据交换 速度最快(无需拷贝) 需手动同步(如配合信号量)
信号量(Semaphore) ❌ 本地 ------(用于同步) ------ 控制资源访问、进程同步 计数灵活,可实现互斥/同步 易死锁,不传数据
信号(Signal) ❌ 本地 通知(无数据或少量) 异步 ------ 异常通知、简单控制 开销极小 不可靠(可能丢失),不能传复杂数据
套接字(Socket) ✅ 支持(TCP/UDP) 双向 可配置 网络通信、本地高性能 IPC(Unix Domain Socket) 通用、跨平台、跨主机 相对复杂,有协议开销

3.3 线程同步

同步机制 作用 是否阻塞 典型用途 C++ 标准库支持 特点
互斥锁(Mutex) 保证同一时间只有一个线程访问临界区 ✅ 阻塞 保护共享数据 std::mutex, std::lock_guard, std::unique_lock 最基础、最常用;防止并发写/读写冲突
递归锁(Recursive Mutex) 允许同一线程多次加锁 ✅ 阻塞 可重入函数 std::recursive_mutex 避免死锁(但应尽量避免设计依赖递归锁)
读写锁(Read-Write Lock) 多个读线程可并发,写线程独占 ✅ 阻塞 读多写少场景 std::shared_mutex (C++17) 提高读密集型性能
条件变量(Condition Variable) 线程等待某个条件成立 ✅ 阻塞 生产者-消费者、线程间通知 std::condition_variable 需配合 mutex 使用;避免忙等待
原子操作(Atomic) 对单个变量的无锁操作 ❌ 非阻塞 计数器、标志位 std::atomic<T> 高性能;仅适用于简单操作(如 ++, compare_exchange)
信号量(Semaphore) 控制同时访问资源的线程数量 ✅ 阻塞 资源池、限流 C++20 起:std::counting_semaphore 可实现更灵活的资源控制(非 C++11~17 原生支持)
屏障(Barrier) 多个线程到达某点后才继续 ✅ 阻塞 并行计算同步 C++20 起:std::barrier 用于阶段式并行任务

3.4 死锁及避免方法

3.4.1 死锁条件

条件 说明
1. 互斥条件(Mutual Exclusion) 资源一次只能被一个线程占用(如 mutex、文件锁)。
2. 占有并等待(Hold and Wait) 线程已持有至少一个资源,同时还在等待其他被占用的资源。
3. 不可抢占(No Preemption) 已分配的资源不能被强制剥夺,只能由持有者主动释放。
4. 循环等待(Circular Wait) 存在一个线程等待环:T₁ → T₂ → ... → Tₙ → T₁。

3.4.2 死锁预防

方法 原理 适用性
固定加锁顺序 破坏循环等待 ✅ 最常用、最有效
std::lock() 标准库自动处理顺序 ✅ 推荐用于多 mutex 场景
超时重试 避免永久等待 ⚠️ 可能活锁,需指数退避
减少锁粒度 降低并发冲突概率 ✅ 提升性能 + 降低死锁风险
无锁编程(atomic 完全避免互斥 ✅ 适用于简单共享状态

4. 网络编程

4.1 IO 多路复用:select/poll/epoll 对比​

对比维度 select poll epoll(Linux 2.6+)
监控方式 基于位图(fd_set),监控文件描述符集合 基于数组(struct pollfd []),存储 fd 和事件类型 基于红黑树(内核维护)和就绪链表,高效存储和查询
最大监控数 受内核参数 FD_SETSIZE 限制(默认 1024) 无理论限制(仅受系统资源限制) 无理论限制(仅受系统资源限制)
IO 事件类型 支持读、写、异常事件 支持读、写、异常事件(可扩展更多事件类型) 支持读、写、异常、边缘触发(ET)等多种事件
效率 每次调用需遍历所有监控 fd,O(n) 复杂度 每次调用需遍历所有监控 fd,O(n) 复杂度 仅遍历就绪 fd,O(1) 复杂度(基于就绪链表)
内存拷贝 每次调用需将 fd_set 从用户态拷贝到内核态 每次调用需将 pollfd 数组从用户态拷贝到内核态 仅初始化时拷贝 fd 到内核态,之后无需拷贝
触发模式 仅水平触发(LT):只要 fd 就绪,每次调用都通知 仅水平触发(LT) 支持水平触发(LT)和边缘触发(ET)
适用场景 监控 fd 数量少(≤1024)的简单场景 监控 fd 数量中等的场景 高并发场景(如百万级连接,Nginx、Redis 使用)

5. 综合知识

相关推荐
浩子智控2 小时前
zynq嵌入式开发(1)—开发准备和流程
linux·嵌入式硬件·硬件架构
仰泳的熊猫2 小时前
题目2086:蓝桥杯算法提高VIP-最长公共子序列
数据结构·c++·算法·蓝桥杯·动态规划
Xzq2105092 小时前
Linux 进程管理:从终端控制到守护进程
linux·运维·服务器
0 0 02 小时前
CCF-CSP 36-2 梦境巡查(dream)【C++】考点:前缀和
开发语言·c++·算法
熊文豪2 小时前
完整卸载 OpenClaw — 各平台卸载完全指南(Windows/macOS/Linux/npm/pnpm)
linux·windows·macos·openclaw
Cx330❀2 小时前
Linux ELF格式与可执行程序加载全解析:从磁盘文件到运行进程
linux·运维·服务器·人工智能·科技
CheungChunChiu2 小时前
USB‑C PD 充电系统完整解析(SC8886 + FUSB302)
linux·usb·type-c·充电
Simplicity_2 小时前
centos docker 部署
linux·docker·centos
Luke Ewin2 小时前
FunASR实时语音识别Websocket接口在Linux服务器中部署教程
linux·服务器·语音识别·funasr·实时语音转写·录音转写