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;
}

输出结果:

正确!

posted @   程序员没有头发  阅读(583)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示