一道c++问题(循环体内的局部变量内存分配和释放)

From: http://www.cnblogs.com/wy-wangyan/archive/2013/04/30/3051487.html

问题如下:

最近查找bug时碰到了循环体中局部变量的内存分配相关的问题,于是查找相关知识,产生了一点疑问。先写代码:

复制代码
 1 int main()
 2 {
 3     int i;
 4     bool bl = true;
 5     for (i=0; i<3; i++)
 6     {
 7         int nvar[10];
 8         if(bl)
 9         {
10             printf("uninitial ");
11             bl = false;
12         }
13         else{
14             printf("before:%d ",nvar[0]);
15         }
16                                  nvar[0] = 10*i;
17         //nvar[i] = 10*i;
18         printf("after:%d\n",nvar[0]);
19     }
20 }
复制代码

实际上,我主要是想看看几个问题:

1、循环体每次循环是否都会为整形数组分配内存

2、每次进入循环时,nvar[0]的值是不是都保留了上一个循环时的值

发现:

1、由于编译器的优化,不会每次循环都会为数组分配内存,而是进入for循环之前一次分配好。

2、每次进入循环时,nvar[0]的值虽然保留了上一个循环的值,但是打印这个值是会报错的,编译器提示变量undefined,因为实际上这个地址对应的变量是一个新的变量,上一个循环产生的变量已经在循环结束时析构。其实把这个数组换成一个类的对象,会更好理解,如下:

复制代码
 1 class B
 2 {
 3 private:
 4     int b;
 5 public:
 6     B()
 7     {
 8         printf("construction function\n");
 9     }
10     B(B &b)
11     {
12         printf("copy construction function\n");
13     }
14     ~B()
15     {
16         printf("destruction function\n");
17     }
18 };
19 
20 int main()
21 {
22                 B class1;
23                 for(int i=0; i<3; i++)
24                 {
25     B bclass1;
26     for (i=0; i<3; i++)
27     {
28         B bclass2 = bclass1;
29                 }
30 }
复制代码

结果:

在回到上面的那个问题,当我把循环体中数据的复制方式换成nvar[i] = 10*i时,就不会产生运行错误。这是为什么?难道这样赋值时,上一次循环的临时对象不会析构吗?

 

我的回答:

临时变量每次循环回收是肯定回收的。我研究了一下,你这个错误是运行时错误,就是未初始化时出现的,属于编译器问题。vc上如果打开了RTC运行时检查就会报这个错,但是gcc上就不会。这个错,我看了一下汇编代码,还是跟编译器有关。编译器在开始的时候给为赋值的数组打了一个标志位。

1 mov    BYTE PTR $T3913[ebp], 0

而循环进行第二次的时候,

1 cmp    BYTE PTR $T3913[ebp], 0
2     jne    SHORT $LN8@main
3     push    OFFSET $LN9@main
4     call    __RTC_UninitUse
5     add    esp, 4

比较发现该数组依然没有初始化,就到了__RTC_UninitUse这个函数报了个错。诡异的是

当  

nvar[i] = 10*i;

 时编译器没有打初始化的标志位。所以也不会报错。原因可能跟编译器有关。

 

结论是,不要把未定义的行为交给编译器去处理。


自己印证了下, linux:

class BASE {
public:
    int a;
    ~BASE() {
        printf("~BASE\n");
    }
};

int main() {

    for (int i = 0; i <= 2; i++) {
        BASE b[2];
        printf("%d\n", b[1].a);
        b[1].a = 9999;
        printf("%p\n", b);
    }
}
输出:

0
0x7fffd1896420
~BASE
~BASE
9999
0x7fffd1896420
~BASE
~BASE
9999
0x7fffd1896420
~BASE
~BASE

对象必然会被解析,这是规范规定的,但是确实空间是被重复利用的.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值