C++内存管理的探讨

开发 后端
大家都知道变量的生存周期这个概念,可是有的时候变量生存周期已经结束,但是所分配的那块内存空间还是存在的。文章举了四个不同的例子,来对C++内存管理进入深度探讨,以说明这其中的原因。

  下边开始对C++内存管理进行探讨:

  先看一段程序:

  1. int main()  
  2. {   
  3.   int i=10;   
  4.   int *j=&i;   
  5.   if(!0)  
  6.   {   
  7.     int l=20;  
  8.     int *k=&l;  
  9.     j=k;  
  10.     k=0;  
  11.   }  
  12.   cout<<*j;  
  13.   return 0;  

  不用编译器,大家想想执行过之后应该打印什么结果?我想大家的***反应应该是打印出一个不确定的数。理由是在if语句里,我们定义了k这个变量,在if执行结束之后,这个变量k所占据的内存是被系统收回的,于是也就造成了变量j所指的结果非常不确定。当然,如果编译并且执行过后,我们发现事情并不是像我们想象的那样,程序最终的打印结果是20,并不是我们期待的一个不确定的数。下面就让我们分析一下原因吧!

  我们用debug的方式来一步一步的分析,在watch的窗口下输入里面所有的变量。

  1. int i=10;  //i is 10 and &i is 0x0012ff7c   
  2. int *j=&i; //*j is 10 and &j is 0x0012ff7c   
  3.       //显然可以看出此时两个变量指的是同一地址   
  4. if(!0)  
  5. {  
  6.   int l=20; //l is 20 and &l is 0x0012ff74   
  7.  
  8.   /*地址0x0012ff7c—0x0012ff75被占据。要说明的是,  
  9.   这个数值很有可能因为电脑硬件的不同而不同。*/   
  10.  
  11.   int *k=&l; //*k is 20 and &k is 0x0012ff74   
  12.  
  13.   //变量k与l指向同一地址。   
  14.  
  15.   j=k;  //j is 0x0012ff74 and *j is 20  
  16.  
  17.   /*指针间的赋值,这个语句的意思是把k指向的地址负值给j。  
  18.   此时这两个变量指向的是同一个地址,都是0x0012ff74,而那  
  19.   块地址存放的是20,所以也就有*j是20的原因。*/   
  20. }  
  21.  
  22. cout<<*j; //*j is 20 and j is 0x0012ff74   
  23.  
  24. /*此时同时可以看到k的地址是0x00000000,说明k这个变量  
  25. 已经被自动销毁,所以地址指零。但是j所指的并不是k,而  
  26. 是k所指的那段地址0x0012ff74,而由于此时j的生存周期还  
  27. 没有结束(j是在if意外定义的),所以j指向的这块地址并  
  28. 没有被收回,也就保存下来20这个数了。*/  

  至此,我们分析完了程序的全过程的内存分配情况,最终结果如下图所示:

内存分配 

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

 

  现在大家应该对上面那个程序的执行过程有一个大概地了解了吧!不过这个还不是我们想要得到的结果,我们需要的是打印一个不确定的结果。有了以上的分析,我们开始新的程序,让他打印出我们想要的东西。

#p#

  对于上面的程序,我们需要改动的是令变量j指向一个地址被释放的位置。于是就有了下面的程序:

  1. int * foo()  
  2. {   
  3.   int l=20;  
  4.   return &l;  
  5. }  
  6.  
  7. int main()  
  8. {  
  9.   int i=10;  
  10.   int *j=&i;  
  11.   j = foo();  
  12.   cout<<*j;  
  13.   return 0;  

  编译器很“聪明”,编译后会给出一个警告。原话是“returning address of local variable or temporary”,指向的是上面程序的第四行,也就是return &l;这条语句。那句英文的意思也不用我再多解释了,相信大家都能看得明白。

  执行的结果,在debug下,是20;在release下,结果是4198795。显然那部分内存被释放掉了。这是因为在debug的程序里面,执行完函数foo,并没有立即释放掉l的那个地址(目前我不清楚这句话说得是否精确)。在这个程序的release版本中,显然程序释放了那部分的地址,所以指向了一个不确定的数。

  这里还要说一件事情,就是在***个程序当中,无论是debug版本还是release版本。执行完那个if语句以后,系统都是不会真正的把l清除掉,l只是k的一个别名。上面的程序是这样写的,用了*j=&i这样一句负值语句,而别名在MSDN中的解释与引用是相同的,所以也可以这样理解,int i=10; int &j=i;与上面的相同。不要去想上面这些程序了,大家再看看下面这个。

  1. void f1( int *& j)  
  2. {   
  3.   int l=20;   
  4.   int *k=&l;   
  5.   j=k;   
  6.   k=0;   
  7. }  
  8. void any_function_use_local_variables()  
  9. {  
  10.   int a,b,c;   
  11.   a=b=c=100;   
  12. }  
  13.  
  14. int main()  
  15. {   
  16.   int i=10;   
  17.   int *j=&i;   
  18.   f1(j);   
  19.   cout<<*j;   
  20.   any_function_use_local_variables();   
  21.   cout<<*j;   
  22.   return 0;  
  23. }  

  请大家自己编译、执行,看看结果是什么,然后结合上面的两个例子,想想是为什么。下面再给大家一个小例子,可能会有助于理解内存的概念。

  程序的过程是试图去增加i,使之超过***的整数。有一种情况是这个值被“卷回来”变成一个负数,在我的机器上程序的打印结果是-2147483648,这个结果可能因为硬件的不同而不同。

  1. int main()  
  2. {   
  3.   int i=1;   
  4.   while(0<i) i++;   
  5.   cout<<i;   
  6.   return 0;  
  7. }  

【编辑推荐】

  1. 内存管理内幕
  2. c++编程常用工具
  3. C++内存管理不同方式分析
  4. 2.2.3 抽象和内存管理
  5. 程序员必看 c++笔试题汇总
责任编辑:韩亚珊 来源: 天极网
相关推荐

2011-07-01 10:16:08

C++内存管理

2023-12-12 13:13:00

内存C++编程语言

2010-02-03 10:50:33

C++多态

2009-09-04 15:53:42

C#内存流

2010-02-04 15:41:10

C++内存管理

2010-02-06 17:09:29

C++文件拷贝

2010-02-04 13:39:44

C++数组参数

2010-01-27 16:10:32

C++静态构造函数

2024-01-22 11:33:17

C++编程语言开发

2010-02-03 10:11:17

C++动态数组

2023-12-31 12:56:02

C++内存编程

2010-02-04 11:15:28

C++模板限制

2010-02-03 16:29:19

C++ sizeof

2010-01-08 16:52:57

C++和C#

2020-11-04 08:37:37

C语言C++内存

2011-06-16 09:28:02

C++内存泄漏

2023-11-17 11:40:51

C++内存

2009-09-01 15:24:59

C++、C#和JAVA

2010-02-03 09:59:42

C++文件流操作

2010-01-11 16:19:05

C++ Builder
点赞
收藏

51CTO技术栈公众号