C++内存布局(vector/虚函数)
今日进度书籍/资料《C Primer》核心章节9.1~9.415.1~15.3实战任务GDB调试一、核心知识复盘1. vector 底层三指针GCC 实现1三个指针_M_start堆内存起始地址_M_finish已存储元素末尾的下一个地址_M_end_of_storage整块分配内存的尾部边界2计算公式size _M_finish - _M_start 当前元素个数capacity _M_end_of_storage - _M_start 最大容纳量3扩容完整流程1判断_M_finish _M_end_of_storage触发扩容2分配更大连续堆内存GCC 默认 2 倍扩容标准无强制倍数3拷贝旧内存所有元素到新内存4释放旧堆内存5更新三指针指向新地址6旧迭代器 / 指针 / 引用全部失效4关键函数区分| reserve (n) | 仅修改_M_end_of_storage| ncapacity 则扩容 | 预分配内存只改容量不改变元素数量 || resize (n) | 修改_M_finish| ncapacity 会扩容 | 改变实际元素个数新增 / 删除元素 || shrink_to_fit () | 全部三指针 | 重新分配等于 size 的内存 | 释放多余堆内存capacitysize || swap () | 交换双方三指针 | 不分配内存 | O (1) 交换地址不拷贝元素 |5emplace_back vs push_backpush_back外部构造对象再拷贝 / 移动进容器emplace_back直接在容器堆内存原地构造对象省去拷贝开销2. 虚函数、vptr、vtable1vptr存在于每个含虚函数对象的头部指向本类虚函数表 vtable2vtable同类对象共用一张存放所有虚函数的地址3纯虚函数virtual func() 0;抽象类 vtable 中纯虚函数对应位置存 nullptr 若实例化抽象类对象调用纯虚函数会解空指针崩溃编译器直接禁止创建抽象类对象。4虚析构必要性 基类析构不加 virtual基类指针 delete 子类对象仅调用基类析构子类堆资源泄漏 加 virtual 后通过对象 vptr 找到子类 vtable先执行子类析构再执行基类析构。3. list 与 vector 核心区别list 节点内存离散不连续无法通过偏移做下标随机访问vector 连续内存支持[]随机访问缓存命中率更高。二、GDB part通过 GDB 直观验证 vector 容量底层逻辑、虚函数 vptr 内存布局从汇编内存层面理解 size/capacity、多态、虚析构原理。实验环境与工程规范规范分层工程源码存放src编译产物输出bin使用 Git 本地归档学习代码实验源码编译与 GDB 启动流程-g参数作用生成调试符号是 GDB 查看底层私有成员_M_impl的必要条件附带 GDB 基础指令讲解。vector 底层三指针观测_M_impl._M_start堆内存起始地址_M_impl._M_finish有效数据末尾地址size _M_finish - _M_start_M_impl._M_end_of_storage堆内存容量边界capacity _M_end_of_storage - _M_start填满容量后 push_back 触发扩容分配全新堆内存旧迭代器全部失效。虚函数 vptr 虚表内存观测单步执行验证虚析构多态调用流程程序正常退出无内存泄漏。实验代码 Git 归档调试完成后将源码与可执行文件提交本地 Git 仓库完成 Day1 学习内容归档。PS:本次使用的指令# 切换到仓库根目录 cd ~/Icymemory # 进入源码文件夹 cd src # 创建day1实验目录 mkdir day1 cd day1 # 创建源码文件 touch gdb_demo.cpp #vim编辑 vim gdb_demo.cpp 按下i插入模式完成后Esc输入:wq保存 # 切回仓库根目录 cd ~/Icymemory # -g 生成GDB调试符号-Wall 开启代码警告 g -g -Wall src/day1/gdb_demo.cpp -o bin/gdb_day1 #启动GDB调试 gdb ./bin/gdb_day1 # 在main函数入口设置断点 b main # 启动程序触发断点 run # 跳过在线调试信息下载提示 n # 打印vector底层三指针核心考点1 print vec._M_impl._M_start print vec._M_impl._M_finish print vec._M_impl._M_end_of_storage # 打印对象内存布局观测头部vptr虚表指针核心考点2 x/16xg p # 退出GDB调试会话 quit # 回到仓库根目录 ~/Icymemory cd ~/Icymemory # 追踪新增源码与可执行文件 git add src/day1 bin/gdb_day1 # 提交记录英文备注避免输入法冲突 git commit -m Day1 GDB test: vector 3 pointers and vptr table memory view三、Known Issuesclass 默认 private 私有继承struct 默认 public 公有继承。私有继承后基类 public 成员在子类权限全部变为 private 私有。swap 交换 vector会改变 capacity,直接互换_M_start/_M_finish/_M_end_of_storage两者 size、capacity 互相交换。const 修饰成员函数作用函数内禁止修改成员变量const 对象只能调用 const 成员函数。无虚析构基类指针 delete 子类对象会怎样没有虚析构就不会走 vptr 查表仅调用基类析构子类资源无法释放内存泄漏。抽象类 vtable 特性抽象类 vtable 中纯虚函数条目是空指针 nullptr编译器禁止实例化防止空指针调用崩溃。emplace_back 优势原地构造省去拷贝。四、手绘图