std::string对象被释放后仍然访问std::string::c_str()返回的指针(访问已经释放掉的内存)的一些总结
一个值得注意的事情
最近在调试项目,发现一个意想不到的问题!程序会偶发性的产生coredump...
先看一下简单化代码:
#include <iostream> using namespace std; const char *test1() { std::string str = "hello"; const char * ptr = str.c_str(); return ptr; } const char *test2() { std::string str = "world"; const char * ptr = str.c_str(); return ptr; } int main() { const char *str1 = test2(); const char *str2 = test1(); std::cout << "str1: " << str1 << std::endl; std::cout << "str2: " << str2 << std::endl; return 0; }
我使用QT的编译器,得出结果:
咋乱码了呢,不应该str1: hello str2: world
这样子的结果吗?程序运行几遍时,有时候会出现正确结果,有时候会乱码而且每一次编译运行的乱码都不一样...
分析原因
以上程序中,函数test1和test2返回一个char*指针,这个指针指向的是函数内部临时新建的std::string对象,但是当函数运行到最后一个花括号}时,里面所有申请的临时对象、变量的内存空间都会被自动释放掉!!!而在主函数使用函数返回的指针char *时,这时候访问的是一个已经释放掉的内存空间,所以打印的是乱码。
但是!我有个疑问,就算内存释放掉了,那块空间的地址之前所存储的内容应该还是会存在的呀!(意思就是说:我就算访问已经释放掉内存,但是内存的内容我没有手动清空,不应该还会存在吗?这时候去访问,不应该还会访问到原来的数据吗?)
深入了解内存回收机制
其实上面这么想也有道理,遇事不决,问问GPT!
我问的太啰嗦了哈哈哈,综上所述,也就是说,当一块内存被手动/自动释放后:
如果系统还没对内存进行回收(清空内存内容;将内存块标记为空闲),这时候去访问是有可能访问到上一次的数据的,但是数据会有乱码、或者被新申请的内存数据覆盖掉,所以是不安全的!
结合大佬的文章《操作系统资源回收问题——delete或者free释放的内存会立即回收到操作系统吗?》
内存(memory)是在堆(heap)上分配的。
当进程 (process)请求内存时是向堆(堆管理器)请求内存,而堆又向操作系统(OS)申请内存。由于这种操作代价比较大,操作系统一般是分配给一块(chunk)内存给堆,以减少内存操作(还是说系统调用)次数。
因此进程调用delete或者free释放资源后,这些资源归还给了这个程序所申请到的堆,而堆不一定会将资源归还给操作系统(取决于操作系统类型、内存块的大小等因素)。
这部分没有归还的资源在当前进程再次(使用new或malloc)申请内存时可以被重用,因此这样可以避免频繁与操作系统进行“内存交互”。这些释放的资源在进程结束后随着整个堆一起归还给OS。
解决方案
我就是要使用函数返回的值,那要怎么做?
直接将返回值赋值std::string对象,让它重新构造一次算了。
#include <iostream> using namespace std; string test1() { std::string str = "hello"; return str; } string test2() { std::string str = "world"; return str; } int main() { //将函数返回值,重新赋值string对象,让其再构造一次,相当于拷贝数据 string str1 = test1(); string str2 = test2(); std::cout << "str1: " << str1.c_str() << std::endl; std::cout << "str2: " << str2.c_str() << std::endl; return 0; }
输出结果:
正确!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库