函数体内变量与对象生命期问题

smallfishff 2008-07-17 09:52:39



#include "stdafx.h"

class cc
{
public:
void pr(void){
printf("OK\n");
};
};

int main(int argc, char* argv[])
{

cc *p=NULL;

{
cc x;
p=&x;
}

p->pr();

return 0;
}




会不会认为以上代码有问题??

只是 栈上的变量或对象的生命期到底是在函数体内还是括号内?我一直认为在函数体内都是有效的.
...全文
231 43 打赏 收藏 转发到动态 举报
写回复
用AI写文章
43 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhoujianhei 2008-07-18
  • 打赏
  • 举报
回复
00411A50 55 push ebp
00411A51 8B EC mov ebp,esp
00411A53 81 EC D8 00 00 00 sub esp,0D8h
00411A59 53 push ebx
00411A5A 56 push esi
00411A5B 57 push edi
00411A5C 8D BD 28 FF FF FF lea edi,[ebp-0D8h]
00411A62 B9 36 00 00 00 mov ecx,36h
00411A67 B8 CC CC CC CC mov eax,0CCCCCCCCh
00411A6C F3 AB rep stos dword ptr [edi]
cc *p=NULL;
// 00411A6E C7 45 F8 00 00 00 00 mov dword ptr [p],0
00411A6E |. C745 F8 00000>mov dword ptr [ebp-8], 0



{
cc x;
p=&x;
// 00411A75 8D 45 EF lea eax,[x]
00411A75 |. 8D45 EF lea eax, dword ptr [ebp-11]
// 00411A78 89 45 F8 mov dword ptr [p],eax
00411A78 |. 8945 F8 mov dword ptr [ebp-8], eax
}

p->pr();
// 00411A7B 8B 4D F8 mov ecx,dword ptr [p]
00411A7B |. 8B4D F8 mov ecx, dword ptr [ebp-8]
00411A7E E8 34 F8 FF FF call cc::pr (4112B7h)

=======================================================
以上是VC编译的,无问题!其它编译器不确定。

zhouzhenyan 2008-07-18
  • 打赏
  • 举报
回复
这代码在vc下跑是没有问题的,同意15楼的说法:思想不对。
NIKE霸天虎 2008-07-18
  • 打赏
  • 举报
回复
在你定义的位置前的一对括号之间
lsd1025 2008-07-18
  • 打赏
  • 举报
回复
括号内,
出了括号自动调用析构函数析构对象了,那段内存置为可用状态,如果没有其他东西占用那段内存里面的东西还在,
但是要是被其他东西占用了就会出错,
这是很危险的指针用法,也就是错误的指针用法。
zdleek 2008-07-18
  • 打赏
  • 举报
回复
C++语法有讲到局部变量的作用范围,楼主复习一下即可确定当然是括号内
Ahaxu 2008-07-18
  • 打赏
  • 举报
回复
[Quote=引用 42 楼 smallfishff 的回复:]
地址未釋放 值還是存在的及指針正確的使用 這些理解當然我都明白.
呵 只是以前還沒看到過哪裡有告訴我 生命期在括號內將結束.以前用if,for語句也沒感覺到.雖然簡單卻不注意.
[/Quote]
对象的生命期是结束了,但是类还在,类中的变量是为每个对象单独构造一个,但是函数是所有变量公用的,有点类似于static变量,所以对象尽管生命期结束,但是类中的函数还是存在的,而且C++编译器对非virtual函数的处理是前绑定,也就是说在编译的时候,所有的函数名已经被换成地址了,对这个pr而言,pr的地址在编译时就确定了,而变量的生命期是在执行的时候确定的,所以,这个pr能执行,但是编译时传到pr里的this是无效地址,所幸的是你的pr()没有调用this。
请认真看下我写的几个程序,除了“震惊!!!”外的已不再是提问,而是答案。
smallfishff 2008-07-18
  • 打赏
  • 举报
回复
地址未釋放 值還是存在的及指針正確的使用 這些理解當然我都明白.
呵 只是以前還沒看到過哪裡有告訴我 生命期在括號內將結束.以前用if,for語句也沒感覺到.雖然簡單卻不注意.
fqli1610 2008-07-18
  • 打赏
  • 举报
回复
学习
yupengchen951124 2008-07-18
  • 打赏
  • 举报
回复
当然有问题了,c++是块(block)语言,作用域在块内,x在下面一个"}"处析勾了
Ahaxu 2008-07-18
  • 打赏
  • 举报
回复
验证程序:
#include "stdafx.h"

class cc
{
public:
void pr(void){
printf("OK\n");
};

};

int main(int argc, char* argv[])
{

cc *p=NULL;

{
cc x;
printf("x.pr=%d\n",x.pr);
p=&x;
}

p->pr();
printf("pr=%d\n",p->pr);

p=p+111111;
p->pr();
printf("p=p+111111后,p->pr=%d\n",p->pr);

cc y;
printf("y.pr=%d\n",y.pr);


return 0;
}
结果:
x.pr=4198405
OK
pr=4198405
OK
p=p+111111后,p->pr=4198405
y.pr=4198405
Press any key to continue
Ahaxu 2008-07-18
  • 打赏
  • 举报
回复

将class cc
{
public:
void pr(void){
printf("OK\n");
};
}改为
class cc
{
public:
int a;
void pr(void){
printf("OK\n");
};
};
后面改变指针p的值时,p->a的值是会变的,而且有的值会使程序崩溃!印证了这个说法“括号内,
出了括号自动调用析构函数析构对象了,那段内存置为可用状态,如果没有其他东西占用那段内存里面的东西还在,
但是要是被其他东西占用了就会出错,
这是很危险的指针用法,也就是错误的指针用法。”

但为什么p->pr()一直不出问题?即使改变p的值使程序崩溃,p->pr()还是正确执行!

这是因为pr的值是前绑定的,在编译的时候都已经被换成具体的地址值了。所以不管p的值如何改变,p->pr的值是固定的。
Ahaxu 2008-07-18
  • 打赏
  • 举报
回复
#include "stdafx.h"

class cc
{
public:
void pr(void){
printf("OK\n");
};
};

int main(int argc, char* argv[])
{

cc *p=NULL;

{
cc x;
p=&x;
}
printf("p=%d\n",p);
p=p+40000;

printf("p=%d\n",p);
p->pr();

return 0;
}

结果:
p=1245048
p=1285048
OK
Press any key to continue

震惊!!!
jiqing_gao 2008-07-17
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 rageliu 的回复:]
代码跑起来应该是没问题的,不过思想是不对的。
这里cc x;已过生命期,之所以跑起来没问题,是因为p->pr();前面没有其他操作,这时p指向的内容虽然生命期已结束,但由于这里没有其他对栈的操作,其存储的内容还没被破坏,如此而已。如果有其他对栈的操作,有可能就破坏了其存储的内容,程序就跑飞了。而如果生命期没过,不管什么对栈的操作,都是不会破坏其内容的
[/Quote]同感
shanying_0 2008-07-17
  • 打赏
  • 举报
回复
路过学习一下
qt_freelancer 2008-07-17
  • 打赏
  • 举报
回复
应该有效的
rageliu 2008-07-17
  • 打赏
  • 举报
回复
代码跑起来应该是没问题的,不过思想是不对的。
这里cc x;已过生命期,之所以跑起来没问题,是因为p->pr();前面没有其他操作,这时p指向的内容虽然生命期已结束,但由于这里没有其他对栈的操作,其存储的内容还没被破坏,如此而已。如果有其他对栈的操作,有可能就破坏了其存储的内容,程序就跑飞了。而如果生命期没过,不管什么对栈的操作,都是不会破坏其内容的
Amuro1987218 2008-07-17
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 akirya 的回复:]
引用 11 楼 Amuro1987218 的回复:
堆上和栈上情况还不太一样,release版恐怕运行1W次也没事

括号里的变量也在栈上开辟,当他西狗时,编译器不会把esp回退,而是继续前进(减操作)

那么这样考虑在函数体内永远有效

这个......你弄一个有指针的class,构造函数分配内存,然后在析构函数中删除指针指的对象
然后那个指针去取这个指针成员的内容。
[/Quote]

这个..是有问题,LZ也说了如果pr那个函数输出一个成员变量就不是预期结果了.

那个回复仅针对1楼贴出来的这部分代码
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 Amuro1987218 的回复:]
堆上和栈上情况还不太一样,release版恐怕运行1W次也没事

括号里的变量也在栈上开辟,当他西狗时,编译器不会把esp回退,而是继续前进(减操作)

那么这样考虑在函数体内永远有效
[/Quote]
这个......你弄一个有指针的class,构造函数分配内存,然后在析构函数中删除指针指的对象
然后那个指针去取这个指针成员的内容。
smallfishff 2008-07-17
  • 打赏
  • 举报
回复

哎呀 按上面所说加个析构函数不就可以证明了嘛!唉!
结果是在括号外结束的.所以生命期在括号内.

事实上编译不会有错误 而且运行正常.如果输出换成变量的话 则会显示乱码 表示内存已经释放了 只是指针还存在.
Amuro1987218 2008-07-17
  • 打赏
  • 举报
回复
堆上和栈上情况还不太一样,release版恐怕运行1W次也没事

括号里的变量也在栈上开辟,当他西狗时,编译器不会把esp回退,而是继续前进(减操作)

那么这样考虑在函数体内永远有效
加载更多回复(23)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧