先别运行 告诉我答案先
#include <fstream.h>
class howmany{
static int object_count;
public:
howmany(){
object_count++;
}
static void print(const char* msg=0)
{
if(msg) cout<<msg<<":";
cout<<"object_cout="
<<object_count<<endl;
}
~howmany(){
object_count--;
print("~howmany()");
}
};
int howmany::object_count=0;
howmany f(howmany x){
x.print("x argument inside f()");
return x;
}
void main() {
howmany h;
howmany::print("after construction of h");
howmany h2=f(h);
howmany::print("after call to f()");
}
看看你家编译器怎么做的!
问题点数:30、回复次数:36Top
1 楼Jokar(贪睡鼠)回复于 2006-10-13 13:58:30 得分 10
ms是 copy constructor 的问题~ 我想说,我家编译器相当的老,相当的不标准;Top
2 楼huangyangman(庸人自扰)回复于 2006-10-13 14:02:38 得分 0
呵呵 学习C++还真是要付出代价啊
还要记这记那的 男人真命苦Top
3 楼Jokar(贪睡鼠)回复于 2006-10-13 14:04:33 得分 0
男人真命苦
----------------
女人命苦的更多~呵呵Top
4 楼Jokar(贪睡鼠)回复于 2006-10-13 14:08:36 得分 0
呵呵~其实 plus个 copy constructor 就行了~Top
5 楼huangyangman(庸人自扰)回复于 2006-10-13 14:12:30 得分 0
你不能再说了 再说我这贴可就没人顶了
呵呵
人气最重要!~
Top
6 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:17:12 得分 10
所以很少用类做参数的,用引用就没问题了。Top
7 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:20:53 得分 0
faint,还有一个陷阱啊。Top
8 楼cwl_feng()回复于 2006-10-13 14:21:43 得分 0
还是养成用引用作参数的好习惯吧,但是谁能解释一下这是为什么呢?Top
9 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:22:10 得分 0
assign constructor也是Top
10 楼Jokar(贪睡鼠)回复于 2006-10-13 14:28:09 得分 0
还是养成用引用作参数的好习惯吧,但是谁能解释一下这是为什么呢?
---------------------------------------
给点提示: howmany h2=f(h); 这句,还有对象拷贝~呵呵
ps:lz不让偶说话,偶就不说了~:)Top
11 楼huangyangman(庸人自扰)回复于 2006-10-13 14:32:29 得分 0
哪有 哪有 开玩笑呢
确实是对象的逐位拷贝,所以没有调用constructor
Top
12 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:32:53 得分 0
唉,还是需要copy constructor函数Top
13 楼huangyangman(庸人自扰)回复于 2006-10-13 14:34:20 得分 0
C++要维护C 还真是花了不少精力哦
感慨~~Top
14 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:35:55 得分 0
对象逐位copy时,static可不是逐位copyTop
15 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:36:47 得分 0
好例子啊。Top
16 楼Jokar(贪睡鼠)回复于 2006-10-13 14:38:11 得分 0
好例子啊。
------------
是呀~蛮经典的~呵呵Top
17 楼huangyangman(庸人自扰)回复于 2006-10-13 14:39:37 得分 0
? 大鸟讲讲
最好来个高手把相关的知识总结一遍
让我好好学习下
Top
18 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:46:08 得分 0
鼠MM都憋半天了,让鼠MM讲吧。Top
19 楼hailongchang(什么时候才能看到星星啊。。。)回复于 2006-10-13 14:50:30 得分 0
鼠MM都憋半天了,让鼠MM讲吧。
==================================
MM,怎么早没看出来?Top
20 楼huangyangman(庸人自扰)回复于 2006-10-13 14:53:21 得分 0
MM==妹妹?
Jokar(贪睡鼠★御姐控☆小宠王)
男人真命苦
----------------
女人命苦的更多~呵呵
难怪说这句话
____________________
顿悟!
Top
21 楼hailongchang(什么时候才能看到星星啊。。。)回复于 2006-10-13 14:54:30 得分 0
还是楼上看贴仔细啊Top
22 楼cwl_feng()回复于 2006-10-13 14:55:36 得分 0
这个程序运行在VS2003下会显示三次条用析构函数,一次是h的,一次是h2的。h2的算h拷贝过去,释放时条用析构函数,第三次是那个对象的?
莫非是x 形参的??
高手赶快冒个泡,解释一下Top
23 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:57:03 得分 0
按照BS的说法,如果t1和t2都是类T的对象,t1=t2的默认含义就是将t2按成员逐个复制到t1。对于包含了由构造函数/析构函数管理的资源的对象而言,按成员复制的语义通常是不正确的。
例:
viud h()
{
T t1;
T t2=t1;
T t3;
t3=t2;
}
默认构造函数被t1、t3各调用一次,一共两次。析构函数对t1、t2、t3各一次,一共3次。
lz的程序也是一样的。只是又转了一个弯,在f()函数的参数调用时,构造生成了局部对象,离开f()时析构。Top
24 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 15:03:31 得分 0
c++函数调用是值传递,也就是类似上面T t2=t1那样生成了一个局部对象,没调默认构造函数,但离开函数时却调了析构函数。Top
25 楼weiym(磨刀霍霍向猪羊)回复于 2006-10-13 15:31:47 得分 0
类都有一个或多个构造函数,一个析构函数和一个赋值操作符,如果不提供就显示将他们定义成Private,可以减少好多类似问题Top
26 楼huangyangman(庸人自扰)回复于 2006-10-13 15:41:25 得分 0
可我正是提供了构造函数和析构函数啊Top
27 楼weiym(磨刀霍霍向猪羊)回复于 2006-10-13 15:52:35 得分 0
加个拷贝构造函数一切就都很明白了Top
28 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 16:05:00 得分 0
可我正是提供了构造函数和析构函数啊
====================
呵呵,正是因为你有才出问题的。要是都没有,所有都是系统默认的,问题也没了。static变量也老实了(根本就不变)。你给它提供了一种构造函数,在拷贝构造时又没用你的构造函数,用了系统自己产生的构造函数,两种构造函数里对资源(把静态变量权且看作资源)处理不一致。更何况每个对象都会用到的那个析构函数里还设计资源处理。这里仅仅是静态变量,还不会出大错,要是用到指针,用到new,delete,呵呵~~~Top
29 楼huangyangman(庸人自扰)回复于 2006-10-13 16:12:25 得分 0
说错了 我要是写的出这么经典的例子就能教书育人了
应该说书上就是提供了构造函数和析构函数啊
这个例子本来就是用来引出copy constructor的 闲来无事 抄了一段上来 呵呵
向前辈们学习.
再给我讲讲调用f()的时候stack frame中是怎么分布的吧 比如说函数的参数,函数的地址,局部变量什么的 月多越好啊
Top
30 楼ugvihc(maybe good good study, hope day day up!)回复于 2006-10-13 16:19:16 得分 0
mark, study...Top
31 楼anrui32(命令提示符(anrui32@163.com))回复于 2006-10-13 17:19:11 得分 0
做个标记,学习Top
32 楼zhulei5()回复于 2006-10-13 17:25:12 得分 0
接分吧Top
33 楼royeleo(煨灶猫||(只要一颗★))回复于 2006-10-13 17:26:50 得分 0
Mark
upTop
34 楼zephyr741(西风)回复于 2006-10-13 18:42:54 得分 10
#include <fstream.h>
class howmany{
static int object_count;
public:
howmany(){
object_count++;
}
static void print(const char* msg=0)
{
if(msg) cout<<msg<<":";
cout<<"object_cout="
<<object_count<<endl;
}
~howmany(){
object_count--;
print("~howmany()");
}
};
int howmany::object_count=0;
howmany f(howmany x){ //这里调用了一次默认copy constructor.
x.print("x argument inside f()");
return x;//又调用了一次copy constructor.
}
void main() {
howmany h;
howmany::print("after construction of h");
howmany h2=f(h);
howmany::print("after call to f()");
}
copy constructor 什么也不做。
所以上面的2次调用不会对object_count 产生任何影响,但是问题就来了, constructor 之后再函数返回的时候堆栈上申请的那个临时的X会被调用destructor.
所以object_count--;
让我们从头开始 看看所有对象的情况
howmany h; // constructor object_count ++;
howmany::print("after construction of h"); //do nothing on object_cout
howmany h2=f(h);// copy constructor do nothing 注意这一句话里面有2次//copyconstructor. 其实还有一次copy assign。不过没有影响,唯一有影响的是在函数返回//的时候调用destructor. object_cout --
howmany::print("after call to f()");//nothing.
//这里会在调用两次destructor 分别destruct h 和 h2
函数的调用方法,调用一个函数的时候会发生一系列的入栈操作,下面这一段是说明stdcall方式的, pascal 和 cdecl 不太一样。
环境win32/vc6
比如有下面这样一个函数
void f( int i, int j ){ int z; }
//
然后调用按照下面这样
extern int i, j;
int res = f( i , j );
转换为汇编的代码应该是下面这个样子
push j; 参数j 进栈
push i; 参数i 进栈
push ebp; ebp 进栈 ebp中存放的是前一个函数调用的ebp地址
mov ebp,esp; // esp放进ebp中
sub esp,4; // 申请变量z
esp是stack-pointer 指向系统当前的堆栈栈顶,这个堆栈只在你自己的进程的地址空间中有效,注意有一点特别的:堆栈是从内存的高地址向低地址方向增长,所以入栈的操作会造成esp的减法操作,不是加法。
上面的前面两行称为函数的pre-prologue; 是操作参数的esp在这中间是有变化,esp = esp - 8;
然后ebp进栈,ebp中保存的是前一个函数的堆栈桢的指针。
堆栈桢就是上面创建的这样一系列的参数包括返回地址还有函数上面申请的临时变量的一段内存空间。
但是ebp并不是指向这个桢的起始位置,而是在桢的中间,他们的内存结构应该是这样
高地址: esp -> 初始位置 参数j
参数i
ebp
变量z
低地址: esp -> 终止位置 栈增长方向是从上往下。
所以几个变量的地址依次是 address of j = [ebp] + 12;
address of i = [ebp] + 8;
address of ebp = [ebp] + 4;
address of z = [ebp] + 0;
....
注: win32 中 int 是4个bytes;
貌似就这么多了,有不对的地方请大家指出,我会改正
另外: 推荐一个好网站: www.codeproject.comTop
35 楼freshlifeO(微微)回复于 2006-10-13 20:02:41 得分 0
markTop
36 楼justrun2005(机枪)回复于 2006-10-16 00:58:54 得分 0
收藏Top




