这样写代码是安全的吗

Z527516197 2011-07-08 07:35:56
如下面的代码所示:

class CIamTemp
{
private:
int m_a;
public:
CIamTemp(){m_a=0;}
~CIamTemp(){}
void SetMemVal(int val)
{
m_a=val;
}
void Dispaly()
{
cout<<"IamTemp's value="<<m_a<<endl;
}
};


CIamTemp& ChangeIamTemp( CIamTemp & iat,int val)
{
iat.SetMemVal(val);
return iat;
}


int main()
{
//下面传递的第一个参数是个临时变量
CIamTemp temp=ChangeIamTemp(CIamTemp(),100);
temp.Dispaly();//显示100

}

据说函数中返回临时变量的引用是非常危险的行为,但是我这里返回的也是临时变量的
引用,用VS2008可以正确编译连接并可以正确运行。这是必然的呢 还是由于当前环境中
变量太少没有覆盖已收回的临时变量的内存空间而偶然出现的现象?

上面代码的汇编如下:

int main()
{
00411590 push ebp
00411591 mov ebp,esp
00411593 push 0FFFFFFFFh
00411595 push offset __ehhandler$_main (415223h)
0041159A mov eax,dword ptr fs:[00000000h]
004115A0 push eax
004115A1 sub esp,0E0h
004115A7 push ebx
004115A8 push esi
004115A9 push edi
004115AA lea edi,[ebp-0ECh]
004115B0 mov ecx,38h
004115B5 mov eax,0CCCCCCCCh
004115BA rep stos dword ptr es:[edi]
004115BC mov eax,dword ptr [___security_cookie (419004h)]
004115C1 xor eax,ebp
004115C3 push eax
004115C4 lea eax,[ebp-0Ch]
004115C7 mov dword ptr fs:[00000000h],eax

CIamTemp temp=ChangeIamTemp(CIamTemp(),100);
004115CD push 64h
004115CF lea ecx,[ebp-0E0h]
004115D5 call CIamTemp::CIamTemp (411005h)
004115DA mov dword ptr [ebp-0E8h],eax
004115E0 mov eax,dword ptr [ebp-0E8h]
004115E6 mov dword ptr [ebp-0ECh],eax
004115EC mov dword ptr [ebp-4],0
004115F3 mov ecx,dword ptr [ebp-0ECh]
004115F9 push ecx
004115FA call ChangeIamTemp (4111D6h)
004115FF add esp,8
00411602 mov edx,dword ptr [eax]
00411604 mov dword ptr [ebp-14h],edx
00411607 mov byte ptr [ebp-4],2
0041160B lea ecx,[ebp-0E0h]
00411611 call CIamTemp::~CIamTemp (41121Ch)

temp.Dispaly();
00411616 lea ecx,[ebp-14h]
00411619 call CIamTemp::Dispaly (4110E6h)

}
0041161E mov dword ptr [ebp-4],0FFFFFFFFh
00411625 lea ecx,[ebp-14h]
00411628 call CIamTemp::~CIamTemp (41121Ch)
0041162D xor eax,eax
0041162F push edx
00411630 mov ecx,ebp
00411632 push eax
00411633 lea edx,[ (411660h)]
00411639 call @ILT+170(@_RTC_CheckStackVars@8) (4110AFh)
0041163E pop eax
0041163F pop edx
00411640 mov ecx,dword ptr [ebp-0Ch]
00411643 mov dword ptr fs:[0],ecx
0041164A pop ecx
0041164B pop edi
0041164C pop esi
0041164D pop ebx
0041164E add esp,0ECh
00411654 cmp ebp,esp
00411656 call @ILT+425(__RTC_CheckEsp) (4111AEh)
0041165B mov esp,ebp
0041165D pop ebp
0041165E ret

在调用display函数时,用的是ecx中存放的指针。但该指针指向的 CIamTemp 在此之前已经调用过析构函数了(黄色的行)。这样怎么也可以?感觉应该出错呀。
...全文
335 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
sivolin 2011-07-17
  • 打赏
  • 举报
回复
那个函数并未构造临时对象,还有一个问题就是既然lz将类的引用作为函数参数,又何必再返回这个类的引用呢?感觉有点多此一举了
uuussseeennn 2011-07-12
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 z527516197 的回复:]

谢谢 my_live_123和 babilife的耐心解答!

我们在做一个项目迁移,从windows平台下迁移到linux下,代码中大量使用了类似
ChangeIamTemp(CIamTemp(),100) 这种用临时变量传参的方法,在gcc下大量报错。
实在找不到好的解决方法。
gcc要求ChangeIamTemp(const CIamTemp & iat,int ……
[/Quote]

我记得g++不会把自定义类型的临时对象当成const的,看来跟gcc有点差别。
qingcairousi 2011-07-12
  • 打赏
  • 举报
回复
mutable关键字。
不过这样就打破const的原则了。
mutable int m_a;
ZYLBLCU 2011-07-12
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 my_live_123 的回复:]

C/C++ code

#include <iostream>
using namespace std;
static int a;
class CIamTemp
{
private:
int m_a;
int count;
public:

CIamTemp()
{
m_a=0;
a++;
count=a;
cout<<"构造……
[/Quote]

不大懂啊,他不是应该在传递之后和temp之后再析构么,那个时候count值已经长起来了,怎么还是析构第一个
FrankHB1989 2011-07-11
  • 打赏
  • 举报
回复
直接返回对象而不是对象引用,参数类型使用非const的右值引用。可以自己定义需要传递的move ctor提升效率。
motzyd 2011-07-10
  • 打赏
  • 举报
回复
gcc要求你加const是因为,gcc不允许修改临时变量,2个方法解决,你可以对const参数进行去const强制转化,或者用最新语法的右值引用&&
一根烂笔头 2011-07-09
  • 打赏
  • 举报
回复

#include <iostream>
using namespace std;
static int a;
class CIamTemp
{
private:
int m_a;
int count;
public:

CIamTemp()
{
m_a=0;
a++;
count=a;
cout<<"构造第"<<a<<"个对象"<<endl;
}
~CIamTemp(){cout<<"析构第"<<count<<"个对象"<<endl;}
void SetMemVal(int val)
{
m_a=val;
}
void Dispaly()
{
cout<<"IamTemp's value="<<m_a<<endl;
}
};


CIamTemp ChangeIamTemp( CIamTemp iat,int val)//注意这里&变化对结果的影响
{
iat.SetMemVal(val);
return iat;
}


int main()
{
//下面传递的第一个参数是个临时变量
//CIamTemp temp=ChangeIamTemp(CIamTemp(),100);//cb不支持
CIamTemp A;//第1个对象
CIamTemp temp;//第2个对象
temp=ChangeIamTemp(A,100);//变成了第一个对象副本
temp.Dispaly();//显示100

CIamTemp temp1;//第3个副本
}



运行结果




CIamTemp ChangeIamTemp( CIamTemp &iat,int val)//注意这里&变化对结果的影响


结果



CIamTemp& ChangeIamTemp( CIamTemp &iat,int val)//注意这里&变化对结果的影响



自己分析吧!很容易明白!
一根烂笔头 2011-07-09
  • 打赏
  • 举报
回复

上面插成超链接了,不好意思
至善者善之敌 2011-07-09
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 z527516197 的回复:]
引用 5 楼 lonelysky 的回复:

这个是引用传参数,返回的也是引用,你那个函数中没有创建任何的临时变量

我知道iat 不是函数ChangeIamTemp创建的临时变量,但是它所指向的的确是个临时变量。
我想知道在函数调用完之后,iat所引用的对象是否还有效;汇编代码显示好像在调用完
ChangeIamTemp之后 ,临时变量就被析构掉了。
还有,这段代码在gcc 4.4……
[/Quote]

我来解释一下,你的程序一共发生了两次析构

一次是这里CIamTemp& ChangeIamTemp( CIamTemp & iat,int val) //当一个类作为参数传递的时候

而正好你的汇编里看到的那条析构语句就是对这里构造的析构

第二次是CIamTemp temp= //构造后的析构


所以你的程序传递的是引用,传递参数的时候不会产生临时变量
一根烂笔头 2011-07-09
  • 打赏
  • 举报
回复

#include <iostream>
using namespace std;
class CIamTemp
{
private:
int m_a;
public:
CIamTemp(){m_a=0;cout<<"构造一个对象"<<endl;}
~CIamTemp(){cout<<"析构一个对象"<<endl;}
void SetMemVal(int val)
{
m_a=val;
}
void Dispaly()
{
cout<<"IamTemp's value="<<m_a<<endl;
}
};


CIamTemp& ChangeIamTemp( CIamTemp &iat,int val)
{
iat.SetMemVal(val);
return iat;
}


int main()
{
//下面传递的第一个参数是个临时变量
//CIamTemp temp=ChangeIamTemp(CIamTemp(),100);//cb不支持
CIamTemp A;
CIamTemp temp=ChangeIamTemp(A,100);
temp.Dispaly();//显示100
}


http://hi.csdn.net/attachment/201107/9/0_13101802713RTP.gif
从结果来看,没有临时对象
Z527516197 2011-07-09
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 lonelysky 的回复:]

这个是引用传参数,返回的也是引用,你那个函数中没有创建任何的临时变量
[/Quote]
我知道iat 不是函数ChangeIamTemp创建的临时变量,但是它所指向的的确是个临时变量。
我想知道在函数调用完之后,iat所引用的对象是否还有效;汇编代码显示好像在调用完
ChangeIamTemp之后 ,临时变量就被析构掉了。
还有,这段代码在gcc 4.4下 编译就通不过。好像不符合C++标准。
Z527516197 2011-07-09
  • 打赏
  • 举报
回复
谢谢 my_live_123和 babilife的耐心解答!

我们在做一个项目迁移,从windows平台下迁移到linux下,代码中大量使用了类似
ChangeIamTemp(CIamTemp(),100) 这种用临时变量传参的方法,在gcc下大量报错。
实在找不到好的解决方法。
gcc要求ChangeIamTemp(const CIamTemp & iat,int val)要加上const。但是函数ChangeIamTemp中需要对iat的值进行更改,所以
又不能加const。很矛盾,还望路过的各位能够指点一二。
懒得打字 2011-07-09
  • 打赏
  • 举报
回复
这个是引用传参数,返回的也是引用,你那个函数中没有创建任何的临时变量
DylanHxxxx 2011-07-08
  • 打赏
  • 举报
回复
mark
Z527516197 2011-07-08
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 hedy007 的回复:]

lz是怎么试出来的?佩服了。
[/Quote]什么怎么试出来的?不明白。
hedy007 2011-07-08
  • 打赏
  • 举报
回复
lz是怎么试出来的?佩服了。
mouse_xie 2011-07-08
  • 打赏
  • 举报
回复
内存没被其他人使用,系统 没那么快把你的内容清除掉。

64,642

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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