如何释放指针又不影响内存数据_你好,C++(78)12.2.1 痛并快乐着:C++中的内存管理...

想要抢先看后面的章节?打赏本文10元,即可获得带插图全本下载地址!
打赏完成记得私信我哦 :p

12.2 智能指针shared_ptr

如果要问程序员们最喜欢C++中的什么特性?那么,C++可以直接操作内存恐怕会是大多数程序员的选择。

而如果要问程序员们最讨厌C++中的什么特性?那么,C++可以直接操作内存恐怕依然是大多数程序员的选择。

12.2.1 痛并快乐着:C++中的内存管理

在C++语言中,可以使用new操作符灵活自由地申请特定大小的内存资源供程序使用,同时又可以利用指向这些内存资源的指针方便地在函数间进行传递,在提高程序性能的同时也增加了程序的灵活性。例如:

#include <iostream>
#include <fstream>
using namespace std;
// 将指针所指向的内存位置上的数据写入文件
bool WriteToFile(const int* pScore,const unsigned int nCount)
{
  ofstream out("data.txt"); // 打开输出文件
  if(!out.is_open()) // 如果文件打开失败
  return false;
  // 通过指针直接访问它所指向的内存位置上的数据
for(unsigned int i = 0; i < nCount; ++i)
  {
  out<<*pScore<<endl; // 直接读取内存位置上的数据并输出
  ++pScore; // 指向下一个数据所在的位置
  }
  out.close();
 
  return true; 
}
 
int main()
{
  while(true) // 构造输入输出无限循环
{
unsigned int N = 0; // 数据个数
   cout<<"请输入数据个数:";
cin>>N;
   // 数据个数为0,循环结束
if(0 == N)
 break;
// 根据需要动态地申请内存资源,得到的指针指向这块内存资源的首地址
int* pScore = new int[N];
   for(unsigned int i = 0;i < N; ++i)
   {
   cout<<"请输入第"<<i+1<<"个数据:";
// 通过指针将输入的数据直接写入相应的内存位置
cin>>*pScore;
  
   ++pScore; // 指向下一个内存位置
   }
   pScore -= N; // 调整指针指向,将其重新指向内存资源的首地址
   // 将指针指向的内存块上的数据写入文件
WriteToFile(pScore,N);
}
 
  return 0;
}

在main()函数的输入输出无限循环中,我们根据用户输入的所需要保存数据的个数N,用new操作符动态地申请了可以保存N个int类型数据的内存资源。同时,让pScore指针指向这块内存资源。然后,在main()函数中,我们通过pScore指针将用户输入的数据直接写入它所指向的内存位置(cin>>*pScore)完成数据的输入。接着,我们将pScore指针重新指向这块内存的起始位置(pScore -= N),并将它传递给WriteToFile()函数。而在这个函数中,我们又同样通过pScore指针参数直接读取内存中的数据写入到ofstream对象(out<<*pScore)完成数据的输出。

到目前为止,似乎一切正常,程序即可以正确输入也可以正确输出。但是,表面的风平浪静并不意味着内部没有暗流涌动。我们不要忘了,这个过程是在一个循环当中的,如果它被反复多次的执行,我们就会发现,程序所占用的内存资源越来越多,最后甚至可能导致系统内存资源耗尽,程序自然也就只有死路一条。

你一定会问,这一切都是为什么?为什么表面上看起来再正确不过的程序最后却走上了内存资源耗尽的不归路?原因就在于C++的内存管理。不同于那些拥有运行时环境的语言(比如Java有Java虚拟机),对于内存资源的使用,它们可以只负责申请而不用负责释放,具体的释放工作由运行时环境帮它们完成。因为没有运行时环境的支持,C++中对内存资源的使用就要麻烦得多,我们既要负责申请,又要在使用完毕后负责释放,两者是一一对应的。可是,一旦程序复杂起来,特别是一个程序由多人协同开发时,往往就很难做到申请与释放的一一对应。

一种情况是,申请的内存资源在使用完毕后没有及时释放产生内存泄漏,最后不断累积导致系统内存资源耗尽。上面的代码就是一个典型的内存泄漏的例子,编写main()函数的程序员在main()函数中用new申请了一块内存资源,但这块内存资源还要留给WriteToFile()函数使用,所以他以为编写WriteToFile()函数的程序员会在使用完毕后释放这块内存资源,于是就没有释放他申请的那块内存资源。可是,编写WriteToFile()函数的程序员认为,这块内存资源不是他申请的,他也不知道main()函数会不会再次使用这块内存资源,所以他也没有释放这块内存资源。这就像一个皮球被踢来踢去,最后的结果就是,谁都没有释放这块内存资源,于是就形成了内存泄漏。如果只是单单的一次内存泄漏也还不太要紧,更要命的是,这个内存泄漏偏偏发生在一个循环当中,随着循环的进行,泄露会不断累积,最后的结果就是程序所占用的内存资源越来越多,导致系统内存资源被耗尽。

与申请的内存忘了释放而导致的内存泄露相对应的还有另外一种情况,那就是一个内存资源有可能被重复释放两次,或者是虽然内存资源已经被释放,但指向这块内存资源的指针依然存在,那么就有可能通过这个指针访问到已经被释放的内存资源,从而导致严重的内存访问错误。依旧是上面的例子,如果编写WriteToFile()函数的程序员认为将数据输出到文件后,对内存的操作就结束了,于是他就主动地用delete操作符释放掉了这块内存资源。可是,对于编写main()函数的程序员来说,他并不知道WriteToFile()函数已经释放了这块内存资源,于是他可能在WriteToFile()函数之后再次使用或者再次释放这块已经被释放的内存资源,程序是无权操作已经被释放的内存资源的,这样的操作会导致严重的内存访问错误。

这就是C++的内存管理,一方面,它可以根据程序需要自由地申请或者释放特定大小的内存资源,可以通过指向这块内存资源的指针对其进行读写或者是灵活地在函数间进行传递,程序员们尽情地享受着直接访问内存资源所带来的快乐;可是在另一方面,如果使用不当,就有可能带来内存泄露或者内存非法访问的严重错误,因此程序员们也同样在忍受着直接访问内存资源所带来的痛苦。痛,并快乐着。

这时的C++程序员们开始羡慕那些拥有运行时环境的开发语言了,对于内存资源,只需要在用到的时候去申请而不用管什么时候释放,运行时环境会负责在这块内存资源使用完毕后自动释放。要是C++中的指针也能这么聪明就好了,知道自己指向的内存资源还有没有人使用,如果没人使用就自动释放,而不用程序员去考虑该何时何地释放。盼星星盼月亮,我们终于在C++11中盼来了这么聪明的智能指针(smart pointer)——shared_ptr。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值