0 问题汇总
以下内容为经过豆包的回答,不一定对,只为自己学习使用
1 C++11有哪些新特性?
- 语言易用性增强
统一的初始化语法
C++11 引入了花括号初始化器(列表初始化),可以用于各种类型的初始化,包括基本类型、数组、容器等,并且可以防止窄化转换。
自动类型推导
auto 关键字:编译器可以根据初始化表达式自动推导变量的类型,减少代码的冗余。
decltype 关键字:用于在编译时推导表达式的类型,常用于模板编程。
范围 for 循环
可以更方便地遍历容器和数组,无需手动管理迭代器或索引。 - 智能指针
C++11 引入了三种智能指针,用于自动管理动态分配的内存,避免内存泄漏。
std::unique_ptr:独占式智能指针,同一时间只能有一个 unique_ptr 指向某个对象。
std::shared_ptr:共享式智能指针,多个 shared_ptr 可以指向同一个对象,通过引用计数来管理对象的生命周期。
std::weak_ptr:弱引用智能指针,用于解决 std::shared_ptr 的循环引用问题。 - 多线程支持
C++11 标准库提供了对多线程编程的原生支持。
std::thread:用于创建和管理线程。
std::mutex 和 std::lock_guard:用于线程同步,std::mutex 是互斥锁,std::lock_guard 是 RAII 风格的锁管理类。 - Lambda 表达式
Lambda 表达式是一种匿名函数,可用于创建临时的、一次性使用的函数对象,常用于函数式编程和作为回调函数。 - 右值引用和移动语义
右值引用:使用 && 表示,用于区分左值和右值,主要用于实现移动语义。
移动语义:通过移动构造函数和移动赋值运算符,避免不必要的对象复制,提高性能。 - 其他特性
std::tuple:用于创建和操作多个不同类型的值的元组。
std::array:是一个固定大小的数组容器,比原生数组更安全和方便。
std::unordered_map 和 std::unordered_set:基于哈希表实现的关联容器,提供了快速的查找和插入操作。
2 一个C++源文件从文本到可执行文件经历的过程
一个 C++ 源文件从文本形式转变为可执行文件,通常要经过预处理、编译、汇编和链接这四个主要阶段,下面为你详细介绍每个阶段的具体内容和作用。
- 预处理阶段
主要任务:预处理器根据源文件里的预处理指令对源文件开展文本替换与处理,最终生成一个经过预处理的中间文件。
常见预处理指令及处理方式
#include:把指定的头文件内容插入到当前源文件里。例如,#include 会将标准输入输出库的头文件内容插入到代码中。
#define:进行宏定义,把代码中出现的宏替换成定义的值。比如 #define PI 3.14159,之后代码里的 PI 都会被替换成 3.14159。
#ifdef、#ifndef、#endif 等:用于条件编译,依据条件决定是否编译某段代码。 - 编译阶段
主要任务:编译器将经过预处理的源文件翻译成汇编代码。在此阶段,编译器会进行语法分析、语义分析、代码优化等操作,同时检查代码中的语法错误和逻辑错误。
工作流程
词法分析:把源代码分解成一个个的词法单元(像关键字、标识符、运算符等)。
语法分析:根据词法单元构建语法树,检查代码是否符合 C++ 语法规则。
语义分析:对语法树进行语义检查,例如类型检查、作用域检查等。
代码优化:对代码进行优化,提升程序的执行效率,例如常量折叠、循环展开等。
生成汇编代码:把优化后的代码转换为汇编语言代码。 - 汇编阶段
主要任务:汇编器将汇编代码转换为机器语言代码,生成目标文件。目标文件是二进制文件,包含了机器指令和数据,但还不能直接运行。
工作方式:汇编器会把汇编指令逐行翻译成对应的机器指令,同时处理符号表和重定位信息。 - 链接阶段
主要任务:链接器将多个目标文件和所需的库文件链接在一起,生成可执行文件。在程序开发中,一个项目通常会包含多个源文件,每个源文件会生成对应的目标文件,同时还可能会使用到系统库或第三方库。链接器的作用就是将这些文件组合成一个完整的可执行程序。
链接类型
静态链接:把库文件的代码直接复制到可执行文件中,这样可执行文件在运行时不需要依赖外部的库文件,但会使可执行文件的体积变大。
动态链接:可执行文件在运行时才会加载所需的库文件,多个程序可以共享同一个库文件,减少了磁盘空间的占用。
综上所述,一个 C++ 源文件从文本到可执行文件需要依次经过预处理、编译、汇编和链接四个阶段,每个阶段都有其特定的任务和作用,最终生成可以在操作系统上运行的可执行程序。
3malloc的原理
malloc 是 C 语言标准库中用于动态内存分配的函数,其原型为 void *malloc(size_t size),作用是在堆内存中分配指定大小(size 字节)的连续空间,并返回一个指向该内存块起始地址的指针。若分配失败,则返回 NULL。下面详细介绍其原理:
堆内存管理基础
在操作系统里,每个进程都有独立的虚拟地址空间,堆是其中用于动态内存分配的区域,它从低地址向高地址增长。操作系统借助特定的数据结构来管理堆内存,记录空闲内存块和已分配内存块的相关信息。
malloc 实现的关键要素
malloc 实现的关键要素
- 空闲内存块管理
空闲链表(Free List):多数 malloc 实现会维护一个空闲链表,用于记录堆中可用的空闲内存块。每个空闲内存块一般包含一个头部信息,其中记录了该内存块的大小以及指向下一个空闲内存块的指针。通过这种链表结构,malloc 可以快速查找和管理空闲内存。
内存池(Memory Pool):为提升内存分配效率,malloc 通常会预先从操作系统申请一大块内存作为内存池。后续的分配和回收操作就在这个内存池中进行,减少了与操作系统的频繁交互。 - 分配算法
首次适配算法(First - Fit):当调用 malloc 时,它会遍历空闲链表,找到第一个大小足够的空闲内存块。若找到合适的内存块,会将其从空闲链表中移除。若该内存块比所需大小大,会将多余部分拆分成一个新的空闲内存块,并重新插入到空闲链表中。
最佳适配算法(Best - Fit):除了首次适配算法,有些实现采用最佳适配算法。此算法会遍历空闲链表,