拓冰建站拓冰建站
首页 / 资讯中心 / 正文

C++内存管理基石:POD类型与面向对象语义解析

C 相关的资源管理这里实现的vector还有一个隐藏很深的bug很难发现涉及的类型与转换逻辑 代码中传入 push_back 的是字符串字面量如 “1111…”其类型是 const char*而 yunze::vector string 的 push_back 期望接收的是 std::string 类型的参数 由于 std::string 类提供了一个非 explicit 的构造函数 std::string(const char*)因此编译器会自动触发隐式类型转换将 const char* 类型的字符串字面量转换为 std::string 临时 std::string 对象再将临时对象传入 push_back完成元素插入。图中插入4组数据没有问题第5组就会出现下图的情况上一篇vector的文章也证实了整型的扩容不会有问题在这里插入图片描述这里肯定是和扩容有关系的插入第5组数据一定会发生扩容 这里调试时将旧空间的数据拷贝给新空间这一步是没有问题的但是旧空间delete后新旧空间都出现问题了在这里插入图片描述这里有一个经验若delete/free出问题了若释放的位置没有问题那就不是这两者导致的就比如说这里delete的指针_start没有变化过一直指向空间开始的位置因为不能部分释放那就不是delete的问题比如说空间开少了越界了也会在delete处报错这里主要是浅拷贝的问题只不过层次更深这里memcpy出现了问题假设调用了push_back(“hello”)这时候vector内部会经历扩容reserve 过程一、先看string对象的内存结构 std::string内部不是直接存字符串而是用指针管理动态内存类似下面的简化版代码语言javascriptAI代码解释class string { private: char* _str; // 指向堆上的字符数组比如hello存这里 size_t _size; // 字符串长度 size_t _cap; // 容量 };比如string s “hello”内存里是这样的代码语言javascriptAI代码解释s: _str → 堆内存地址0x100存着h,e,l,l,o,\0 _size 5 _cap 5二、旧代码用memcpy复制的问题浅拷贝的坑 这里的的reserve函数里用memcpy复制旧数据到新空间代码语言javascriptAI代码解释memcpy(tmp, _start, sizeof(T) * sz); // T是string时这里出问题memcpy的本质是“按字节复制内存”它不管对象内部的逻辑只把旧对象的二进制数据原封不动搬到新空间。 当T是string时复制后新空间的string对象会变成这样代码语言javascriptAI代码解释旧空间的string对象s_old _str → 0x100堆上的hello 新空间的string对象s_newmemcpy复制后 _str → 0x100和s_old的_str完全一样 _size 5复制了s_old的_size _cap 5复制了s_old的_cap这时候s_old和s_new的_str指针指向同一块堆内存0x100这就是 “浅拷贝”—— 只复制了指针没复制指针指向的实际数据。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门