浅谈C++中的内存管理

2016-02-19 20:02 11 1 收藏

今天图老师小编要跟大家分享浅谈C++中的内存管理,精心挑选的过程简单易学,喜欢的朋友一起来学习吧!

【 tulaoshi.com - 编程语言 】

摘要:

  大家都知道变量的生存周期这个概念,可是有的时候变量生存周期已经结束,但是所分配的那块内存空间还是存在的。文章举了四个不同的例子,来说明这其中的原因。   前言:

  前一段时间在一个好友的的博客论坛上看到他学习C++时碰到的一小点问题,是关于C++中最基本的内存分配方面的。其实对于内存这东西,除了知道我自己用的是256M的内存以外,我也不太清楚他到底里面是怎么工作的。看了大师们的讲解,我深有体会,把这些讲解整理出来,为所有C++的newbie们共勉!  正文:  事情是因为这样一小段程序而来的。int main()
{
  int i=10;
  int *j=&i;
  if(!0)
  {
  int l=20;
  int *k=&l;
  j=k;
  k=0;
  }
  cout*j;
  return 0;
}  不用编译器,大家想想执行过之后应该打印什么结果?我想大家的第一反应应该是打印出一个不确定的数。理由是在if语句里,我们定义了k这个变量,在if执行结束之后,这个变量k所占据的内存是被系统收回的,于是也就造成了变量j所指的结果非常不确定。当然,假如编译并且执行过后,我们发现事情并不是像我们想象的那样,程序最终的打印结果是20,并不是我们期待的一个不确定的数。下面就让我们分析一下原因吧!  我们用debug的方式来一步一步的分析,在watch的窗口下输入里面所有的变量。int i=10;  //i is 10 and &i is 0x0012ff7c
int *j=&i; //*j is 10 and &j is 0x0012ff7c
  //显然可以看出此时两个变量指的是同一地址
if(!0)
{
  int l=20; //l is 20 and &l is 0x0012ff74   /*地址0x0012ff7c—0x0012ff75被占据。要说明的是,
  这个数值很有可能因为电脑硬件的不同而不同。*/   int *k=&l; //*k is 20 and &k is 0x0012ff74   //变量k与l指向同一地址。   j=k;  //j is 0x0012ff74 and *j is 20  /*指针间的赋值,这个语句的意思是把k指向的地址负值给j。
  此时这两个变量指向的是同一个地址,都是0x0012ff74,而那
  块地址存放的是20,所以也就有*j是20的原因。*/
}cout*j; //*j is 20 and j is 0x0012ff74 /*此时同时可以看到k的地址是0x00000000,说明k这个变量
已经被自动销毁,所以地址指零。但是j所指的并不是k,而
是k所指的那段地址0x0012ff74,而由于此时j的生存周期还
没有结束(j是在if意外定义的),所以j指向的这块地址并
没有被收回,也就保存下来20这个数了。*/  至此,我们分析完了程序的全过程的内存分配情况,最终结果是这样的。(图1)

  我们同时也可以在Memory里面看看这个地址的具体内容。我们可以看到是14,这是十六进制的数,化成十进制,正好是20。(图2)

  现在大家应该对上面那个程序的执行过程有一个大概地了解了吧!不过这个还不是我们想要得到的结果,我们需要的是打印一个不确定的结果。有了以上的分析,我们开始新的程序,让他打印出我们想要的东西。  对于上面的程序,我们需要改动的是令变量j指向一个地址被释放的位置。于是就有了下面的程序。int * foo()
{
  int l=20;
  return &l;
}int main()
{
  int i=10;
  int *j=&i;
  j = foo();
  cout*j;
  return 0;
}  编译器很“聪明”,编译后会给出一个警告。原话是“returning address of local variable or temporary”,指向的是上面程序的第四行,也就是return &l;这条语句。那句英文的意思也不用我再多解释了,相信大家都能看得明白。  执行的结果,在debug下,是20;在release下,结果是4198795。显然那部分内存被释放掉了。这是因为在debug的程序里面,执行完函数foo,并没有立即释放掉l的那个地址(目前我不清楚这句话说得是否精确)。在这个程序的release版本中,显然程序释放了那部分的地址,所以指向了一个不确定的数。 更多内容请看C/C++技术专题  揭秘Linux内存治理  网络治理实用手册专题,或 这里还要说一件事情,就是在第一个程序当中,无论是debug版本还是release版本。执行完那个if语句以后,系统都是不会真正的把l清除掉,l只是k的一个别名。上面的程序是这样写的,用了*j=&i这样一句负值语句,而别名在MSDN中的解释与引用是相同的,所以也可以这样理解,int i=10; int &j=i;与上面的相同。不要去想上面这些程序了,大家再看看下面这个。
   void f1( int *& j)
{
  int l=20;
  int *k=&l;
  j=k;
  k=0;
}
void any_function_use_local_variables()
{
  int a,b,c;
  a=b=c=100;
}int main()
{
  int i=10;
  int *j=&i;
  f1(j);
  cout*j;
  any_function_use_local_variables();
  cout*j;
  return 0;
}  请大家自己编译、执行,看看结果是什么,然后结合上面的两个例子,想想是为什么。下面再给大家一个小例子,可能会有助于理解内存的概念。  程序的过程是试图去增加i,使之超过最大的整数。有一种情况是这个值被“卷回来”变成一个负数,在我的机器上程序的打印结果是-2147483648,这个结果可能因为硬件的不同而不同。int main()
{
  int i=1;
  while(0i) i++;
  couti;
  return 0;
}   结束。 更多内容请看C/C++技术专题  揭秘Linux内存治理  网络治理实用手册专题,或

来源:http://www.tulaoshi.com/n/20160219/1622591.html

延伸阅读
假如一个人自称为程序高手,却对内存一无所知,那么我可以告诉你,他一定在吹牛。 !-- frame contents -- !-- /frame contents -- 用C或C++写程序,需要更多地关注内存,这不仅仅是因为内存的分配是否合理直接影响着程序的效率和性能,更为主要的是,当我们操作内存的时候一不小心就会出现问题,而且很多时候,这些问题都是不易发觉...
尽管这个概念已经让人说滥了 ,还是想简单记录一下, 以备以后查询。 代码如下: #ifdef _DEBUG #define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__) #else #define DEBUG_CLIENTBLOCK #endif #define _CRTDBG_MAP_ALLOC #include crtdbg.h #ifdef _DEBUG #define new DEBUG_CLIENTBLOCK #endif int _tmain(int ...
当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道.这些往往会使人受尽折磨.所以如果你想深入C/C++编程,你必须静下心来,好好苦一番. 现在我们将讨论C/C++里我认为哪一本书都没有完全说清楚,也是涉及概念细节最多,语言中最难的技术之一的动态内存的传递.并且在软件开发中很多专业人员并不能写出相关的合格的代码. ...
三层架构并不是MVC,MVC是一个很早就有的经典的程序设计模式,M-V-C分为三层,M(Model)-V(View)-C(Control)。而web开发中的三层架构是指:数据访问层(DAL-DatabaseAccessLayer),业务逻辑层(BLL-BusinessLoginLayer),以及用户界面层(UI-UserInterface,实际就是网页后台的具体调用BLL层)。这个是基本概念。曾经我以为三层架构就是在AppCode中...
函数存放在内存的代码区域内,它们同样有地址,我们如何能获得函数的地址呢? 假如我们有一个int test(int a)的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。 !-- frame contents -- !-- /frame contents -- 定义一个指向函数的指针用如下的形式,以上面的test()为例: ...

经验教程

520

收藏

59
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部