商量C++ 变量生命周期、栈分派体式格式、类内存布局、Debug和Release法度的差别(一)
添加时间:2013-6-20 点击量:
今天看博客园的文章,发明博问栏目中有一个网友的题目挺有趣的,就点进去看了下,题目是“C++生活生计期题目”,给出链接:http://q.cnblogs.com/q/51133/
本文会以此题目作为评论辩论的实例,来具体评论辩论以下四个题目:
(1) C++变量生命周期
(2) C++变量在栈平分派体式格式
(3) C++类的内存布局
(4) Debug和Release法度的差别
也许您感觉这些评论辩论题目没有实际意义,应当多做些进步临盆力的工作,如同反复发明轮子也是没有意义的。
笔者赞成这个概念,然则,作为一个有寻求的法度员,应当知其然并且知其所以然,更应当知道轮子是怎么造出来的,不是吗?
当然,限于篇幅,本文可能只是抛砖引玉,更多的常识,必然是大师本身去摸索的。
不久不多说,进入正题。
实验景象:Win7 32bit体系 + VS2008 SP1
题目现象:
先浏览以下法度:
#include stdafx.h
#include<iostream>
#include<windows.h>
using namespace std;
class T
{
protected:
int t;
public:
T(int r=0):t(r){}
void showNum(){cout<<t<<endl;}
};
class T1:public T
{
private:
int x;
public:
T1(int r):x(r),T(r){}
void show(){cout<<x=<<x<<endl;}
};
class T2:public T
{
private:
int x;
public:
T2(int r):x(rr),T(r){}
void show(){cout<<x=<<x<<endl;}
};
void main()
{
T p[10];
for(int i=0;i<5;i++)
{
if(i%2==0)
{
T1 r(2);
p[i]=&r;
cout<<&r<<endl;
}
else
{
T2 r(3);
p[i]=&r;
cout<<&r<<endl;
}
}
for(int i=5;i<10;i++)
{
if(i%2==0)
{
T1 r(4);
p[i]=&r;
cout<<&r<<endl;
}
else
{
T2 r(5);
p[i]=&r;
cout<<&r<<endl;
}
}
for(int i=0;i<10;i++)
{
p[i]->showNum();
}
system(pause);
}
不急着往下看,先猜测此法度输出。
一般来说,我们猜测的输出会是什么成果呢?
起首Debug版本和Release版本应当输出成果是雷同的,或者规律是雷同的。
当0 <= i < 5时,输出5个地址,应当是不合的,逐个递增,生成的局部变量存放在栈中;
当5 <= i < 10时,又输出5个地址,应当也是不合的,也是逐个递增,生成的局部变量存放在栈中;
最后轮回调用p[i]->showNum()这个办法10次,输出的成果应当是不成知的,因为P[i]指向的对象都已经失效。
我们来看看实际输出的成果:
Debug版本:
当0 <= i < 5时,输出5个地址,是一种瓜代状输出,分别是001FF750和001FF740。
当5 <= i < 10时,又输出5个地址,也是瓜代状输出,分别是001FF714和001FF724。
最后轮回调用p[i]->showNum()这个办法10次,输出的成果是正确的,似乎那些栈中的局部对象未失效。
Release版本:
当0 <= i < 5时,输出5个地址,是一种瓜代状输出,分别是001CFB00和001CFB08。
当5 <= i < 10时,又输出5个地址,也是瓜代状输出,新鲜的是地址的值也是001CFB00和001CFB08。
最后轮回调用p[i]->showNum()这个办法10次,输出的成果满是5和4,似乎前5次输出失效了,后5次没有失效。
为什么?
大师可以先思虑,限于篇幅,笔者的下一篇博客将给出具体的解析。
彼此相爱,却不要让爱成了束缚:不如让它成为涌动的大海,两岸乃是你们的灵魂。互斟满杯,却不要同饮一杯。相赠面包,却不要共食一个。一起歌舞欢喜,却依然各自独立,相互交心,却不是让对方收藏。因为唯有生命之手,方能收容你们的心。站在一起却不要过于靠近。—— 纪伯伦《先知》
今天看博客园的文章,发明博问栏目中有一个网友的题目挺有趣的,就点进去看了下,题目是“C++生活生计期题目”,给出链接:http://q.cnblogs.com/q/51133/
本文会以此题目作为评论辩论的实例,来具体评论辩论以下四个题目:
(1) C++变量生命周期
(2) C++变量在栈平分派体式格式
(3) C++类的内存布局
(4) Debug和Release法度的差别
也许您感觉这些评论辩论题目没有实际意义,应当多做些进步临盆力的工作,如同反复发明轮子也是没有意义的。
笔者赞成这个概念,然则,作为一个有寻求的法度员,应当知其然并且知其所以然,更应当知道轮子是怎么造出来的,不是吗?
当然,限于篇幅,本文可能只是抛砖引玉,更多的常识,必然是大师本身去摸索的。
不久不多说,进入正题。
实验景象:Win7 32bit体系 + VS2008 SP1
题目现象:
先浏览以下法度:
#include stdafx.h
#include<iostream>
#include<windows.h>
using namespace std;
class T
{
protected:
int t;
public:
T(int r=0):t(r){}
void showNum(){cout<<t<<endl;}
};
class T1:public T
{
private:
int x;
public:
T1(int r):x(r),T(r){}
void show(){cout<<x=<<x<<endl;}
};
class T2:public T
{
private:
int x;
public:
T2(int r):x(rr),T(r){}
void show(){cout<<x=<<x<<endl;}
};
void main()
{
T p[10];
for(int i=0;i<5;i++)
{
if(i%2==0)
{
T1 r(2);
p[i]=&r;
cout<<&r<<endl;
}
else
{
T2 r(3);
p[i]=&r;
cout<<&r<<endl;
}
}
for(int i=5;i<10;i++)
{
if(i%2==0)
{
T1 r(4);
p[i]=&r;
cout<<&r<<endl;
}
else
{
T2 r(5);
p[i]=&r;
cout<<&r<<endl;
}
}
for(int i=0;i<10;i++)
{
p[i]->showNum();
}
system(pause);
}
不急着往下看,先猜测此法度输出。
一般来说,我们猜测的输出会是什么成果呢?
起首Debug版本和Release版本应当输出成果是雷同的,或者规律是雷同的。
当0 <= i < 5时,输出5个地址,应当是不合的,逐个递增,生成的局部变量存放在栈中;
当5 <= i < 10时,又输出5个地址,应当也是不合的,也是逐个递增,生成的局部变量存放在栈中;
最后轮回调用p[i]->showNum()这个办法10次,输出的成果应当是不成知的,因为P[i]指向的对象都已经失效。
我们来看看实际输出的成果:
Debug版本:
当0 <= i < 5时,输出5个地址,是一种瓜代状输出,分别是001FF750和001FF740。
当5 <= i < 10时,又输出5个地址,也是瓜代状输出,分别是001FF714和001FF724。
最后轮回调用p[i]->showNum()这个办法10次,输出的成果是正确的,似乎那些栈中的局部对象未失效。
Release版本:
当0 <= i < 5时,输出5个地址,是一种瓜代状输出,分别是001CFB00和001CFB08。
当5 <= i < 10时,又输出5个地址,也是瓜代状输出,新鲜的是地址的值也是001CFB00和001CFB08。
最后轮回调用p[i]->showNum()这个办法10次,输出的成果满是5和4,似乎前5次输出失效了,后5次没有失效。
为什么?
大师可以先思虑,限于篇幅,笔者的下一篇博客将给出具体的解析。
彼此相爱,却不要让爱成了束缚:不如让它成为涌动的大海,两岸乃是你们的灵魂。互斟满杯,却不要同饮一杯。相赠面包,却不要共食一个。一起歌舞欢喜,却依然各自独立,相互交心,却不是让对方收藏。因为唯有生命之手,方能收容你们的心。站在一起却不要过于靠近。—— 纪伯伦《先知》