C++栈内存探究

本来以为不会遇到这个蠢问题:一个局部变量可以在其作用域之外访问么?但是在仿写别人的stl的时候,发现他有这个问题,而这个问题又引发了另一个问题:为啥指针访问临时变量地址总不变?
啊,对了,这是上面的问题的答案:

局部变量确实是不可以被外部使用的。

这种情况只是恰巧那块内存区是存在的,但它并不属于 foo 函数里的 a 所有,
在实际编程中一定不要这么用,很大概率程序会崩溃。

下面就是我用来探究这个问题的小程序:

#include <iostream>

class node{
public:
      node(int a):i(a){}
      int i;
};

class node_iterator{
public:
      node_iterator(node* a):i(a){}
      node* i;
};

node_iterator test(node i){
      node a(i);
      return node_iterator(&a);
}

void stack_occupy(){
      int i = 1;
      //int j[120];
      std::cout << &i << std::endl;
      std::cout << "5: " << test(5).i << std::endl;
      std::cout << "6: " << test(6).i << std::endl;
}

int main(){
      node *tem1, *tem2;
      std::cout << "1: " << test(1).i << std::endl;
      if((tem1=test(2).i)==(tem2=test(3).i)) std::cout << "equal " << "2: " << tem1 << " 3: " << tem2 << std::endl;
      std::cout << "4: " << test(4).i << std::endl;
      stack_occupy();
      std::cout << "7: " << test(7).i << std::endl;

      return 0;
}

注释掉int j[120];:

1: 0x61fec8
equal 2: 0x61fec8 3: 0x61fec8
4: 0x61fec8
0x61fec4
5: 0x61fe98
6: 0x61fe98
7: 0x61fec8

做实验时,我又发现了新的问题:变量在栈内存中的排布其实并不是完全连续的,似乎和命名空间、作用域之类的有关,比如函数stack_occupy()里的int i在栈内存中就是紧挨着之前的临时变量反复使用的空间0x61fec8的。但是在该函数里又产生了一层作用域(也就是在stack_occupy里再调用test)时,会空出一大段空间。这种分层分块的做法让我想到了STL中Alloc使用的内存池技术,大概这种分配内存的方式编译效率更高吧,不用多一个变量申请一次。我算了一下,间隔为0x30,换算成十进制,也就是480byte。对于我的g++版本来说,一个int是4byte,所以是120个int。我就想看看这一个作用域要是被填满了,下一个作用域的内存起点是多少,就把int j[120];的注释删掉了:

1: 0x61fec8
equal 2: 0x61fec8 3: 0x61fec8
4: 0x61fec8
0x61fec4
5: 0x61fcb8
6: 0x61fcb8
7: 0x61fec8

始终要注意:除了动态申请的内存(在堆内存里),在其他区域的内存(不止栈内存,还有静态区之类的)在程序运行前,都被编译器分配好了。爱怎么分配是编译器决定的,我们现在这个例子把几次局部变量都分配在同一个起点,不一定每个编译器次次都这样,怎么做完全取决于编译器是怎么设计的。我举个例子:编译器可能认为(因为是我猜的)需要反复申请 nodeint大小的内存(就你1234567的操作),所以正常程序运行时,本来int i也可以放在0x61fec8这个位置的(因为之前的临时变量已经销毁了),然后7号操作申请的临时变量排在int i后面,但编译器并没有这么做,因为编译器认为把这个位置空出来留给后面的可能效率更高。这完全取决于编译器怎么设计。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值