怪了,引用的地址竟然和变量的地址不同???

luozuwu 2009-11-19 07:58:36
#include<iostream.h>
class A
{
public:
A(int i){x=i;}
A(A &a){this->x=a.x;}
int x;

};
A fun()
{
A a(10);
return a;
}
void main()
{
A &r=fun();
cout<<"the address of r "<<&r<<endl;
cout<<"the address of temp "<<&fun()<<endl;
}
&fun()是否表示fun()函数返回的临时对象的地址?
如果是,那为什么引用r的地址和该临时对象的地址不同???
...全文
372 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
forster 2009-11-20
  • 打赏
  • 举报
回复
调用两次 还都是局部的。。
2009-11-20
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 jinhao 的回复:]
别用VC6了
[/Quote]
正解
天亮后说晚安 2009-11-20
  • 打赏
  • 举报
回复
jiefen通道
lzh3ng 2009-11-20
  • 打赏
  • 举报
回复
学习了。。。。
musezh2 2009-11-20
  • 打赏
  • 举报
回复
留贴下次仔细看
maquan 2009-11-20
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 shelok 的回复:]
在你说胡说八道之前,我推荐你看stl之父是如何运用这个特性的:
http://www.ddj.com/cpp/184403758
你要检验标准,永远别拿VC,记住了
[/Quote]
首先声明,那个“××××”不是我说的,我是不赞同粗口的 ^_^

你推荐的这篇文章我看了,在里面找到了关于“the C++ Standard”的描述,原文是:
a reference initialized with a temporary value makes that temporary value live for the lifetime of the reference itself.

如果让我来翻译的话,我觉得 yndfcd 老弟的说法是正确的。“the lifetime of the reference itself”显然是在函数返回的那个点上就终止了,所以在返回之后再去使用它,就是一个典型的“悬挂引用”了。

至于那位大佬使用这条标准的例子,也就是那个 MakeGuard(),其实返回值本身并不是一个 reference,而是一个 value,也就是说,在其返回的瞬间是发生了拷贝复制的,返回后再使用的是复制出来的新对象。他那个例子的要点是说把 MakeGuard() 的返回值赋值给一个 reference,从而使这个 value 的生存期延迟到函数结束,在那个瞬间再进行析构(从而确保文件被关闭)。
shelok 2009-11-20
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 yndfcd 的回复:]
纯粹是胡说八道.

标准说的是,当把一个临时变量绑定到一个const引用时,该临时变量的生存期会延长到const引用的生存期.而不是,返回局部变量的const引用,该局部变量不会马上析构,其生命周期等同返回的const引用.

当函数返回一个const引用时,情况如下
 
C/C++ codeconst T& ret= D();return ret;

显然ret的生存期在函数结束时,就己经结束了.于是D()产生的临时对象也析构了.VS2008在这点上是符合标准的.
[/Quote]


在你说胡说八道之前,我推荐你看stl之父是如何运用这个特性的:
http://www.ddj.com/cpp/184403758

你要检验标准,永远别拿VC,记住了
herman~~ 2009-11-20
  • 打赏
  • 举报
回复
我晕,两次调用构建了两个不同的对象,返回的地址不一样是正常的吧
underuwing 2009-11-20
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 style_2009 的回复:]
进行了两次调用,产生了两个相同类型对象,并且你函数的返回方式会对函数中产生的对象进行一次复制,如果加上这样一个构造函数:
A(){cout < <"Construct" < <endl;}
的话你会看到四次输出。
[/Quote]
我试验了一下,只能看到两次。
maquan 2009-11-20
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 yndfcd 的回复:]
标准说的是,当把一个临时变量绑定到一个const引用时,该临时变量的生存期会延长到const引用的生存期.而不是,返回局部变量的const引用,该局部变量不会马上析构,其生命周期等同返回的const引用.
[/Quote]
hehe,不错,经验证,的确如此。这个标准看上去“顺眼”多了 ^_^

程序如下:
void testSyntax4() 
{
D();
printf( "separator 1\n" );
const B& ref = D();
printf( "separator 2\n" );
D();
printf( "separator 3\n" );
}

运行结果如下:

B ctor: 0012FD94
D ctor: 0012FD94
B dtor: 0012FD94
separator 1
B ctor: 0012FE6C
D ctor: 0012FE6C
separator 2
B ctor: 0012FDA0
D ctor: 0012FDA0
B dtor: 0012FDA0
separator 3
B dtor: 0012FE6C <-- 这说明,被 const B& ref 所引用那个对象是在返回的瞬间才析构的,而其它的对象是当时就析构了
yndfcd 2009-11-20
  • 打赏
  • 举报
回复
纯粹是胡说八道.

标准说的是,当把一个临时变量绑定到一个const引用时,该临时变量的生存期会延长到const引用的生存期.而不是,返回局部变量的const引用,该局部变量不会马上析构,其生命周期等同返回的const引用.

当函数返回一个const引用时,情况如下

const T& ret = D();

return ret;


显然ret的生存期在函数结束时,就己经结束了.于是D()产生的临时对象也析构了.VS2008在这点上是符合标准的.
maquan 2009-11-20
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 shelok 的回复:]
补充一下,如果非要返回临时变量的引用,就返回const引用,按C++标准,返回局部变量的const引用,该局部变量不会马上析构,其生命周期等同返回的const引用.这样是有好处的,避免了二次拷贝,如果有类层次,避免基类虚函数;[/Quote]
个人认为,这个“标准”恐怕是难以实现的。你可以在语法上这样规定,编译器也可以按照这个约定改变调用析构函数的时机,但是编译器怎么能够阻止后续的程序使用堆栈呢?局部变量是建立在堆栈中的,函数返回后,堆栈已经弹出来了……
maquan 2009-11-20
  • 打赏
  • 举报
回复
不好意思,上面少贴了 class B 的代码:
class B
{
public:
B() {
printf( "B ctor: %08X\n", this );
}

~B() {
printf( "B dtor: %08X\n", this );
}

void DoSomething() const {
printf( "B DoSomething: %08X\n", this );
}
};
maquan 2009-11-20
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 shelok 的回复:]
补充一下,如果非要返回临时变量的引用,就返回const引用,按C++标准,返回局部变量的const引用,该局部变量不会马上析构,其生命周期等同返回的const引用.这样是有好处的,避免了二次拷贝,如果有类层次,避免基类虚函数;
C/C++ codeclass B
{public:
B();void DoSomething(){};~B();
}class D :public B
{public:
D();
}const B& Get()
{return D();
}const B* GetPoint()
{const pB*=new D();return pB;
}int main()
{
Get().DoSomeThing();//此处避免了D的拷贝,而且析构的时候是D的析构,不用B声明virtual析构函数
GetPoint()->DoSomeThing();//如果不用智能指针包装,内存泄露,如果用智能指针,B要声明virtual析构函数return1;
}
[/Quote]

还有这种说法?学习了!

不过,怎么在我这里跑的结果跟你说的不太一样?难道 VS2008 不再遵守这个标准了?
class D : public B
{
public:
D() {
printf( "D ctor: %08X\n", this );
}
};

const B& Get()
{
return D();
}

const B* GetPoint()
{
const B* pB = new D();
return pB;
}

void testSyntax3()
{
Get().DoSomething(); // 此处避免了D的拷贝,而且析构的时候是D的析构,不用B声明virtual析构函数
GetPoint()->DoSomething(); // 如果不用智能指针包装,内存泄露,如果用智能指针,B要声明virtual析构函数
}

运行结果如下:

B ctor: 0012FCF3
D ctor: 0012FCF3
B dtor: 0012FCF3 <-- 看这里,析构了!
B DoSomething: 0012FCF3
B ctor: 00C541B0
D ctor: 00C541B0
B DoSomething: 00C541B0

显然在调用 DoSomething() 之前,对象就析构了!
lovesi3344 2009-11-20
  • 打赏
  • 举报
回复
珍爱生命,远离VC6!!
珍爱生命,远离VC6!!!
珍爱生命,远离VC6!!!!
shelok 2009-11-19
  • 打赏
  • 举报
回复
补充一下,如果非要返回临时变量的引用,就返回const引用,按C++标准,返回局部变量的const引用,该局部变量不会马上析构,其生命周期等同返回的const引用.这样是有好处的,避免了二次拷贝,如果有类层次,避免基类虚函数;

class B
{
public:
B();
void DoSomething(){};
~B();
}
class D : public B
{
public:
D();
}
const B& Get()
{
return D();
}
const B* GetPoint()
{
const pB* = new D();
return pB;
}
int main()
{
Get().DoSomeThing();//此处避免了D的拷贝,而且析构的时候是D的析构,不用B声明virtual析构函数
GetPoint()->DoSomeThing();//如果不用智能指针包装,内存泄露,如果用智能指针,B要声明virtual析构函数
return 1;
}

这种用法也很普遍,比如:

void Person::SetGender(cosnt std::string& gender)
{
m_strGender = gender;
}
const std::string& parse_gender(int eGender)
{
eGender == 1 ? "male" : "female";
}
//就可以这样使用,避免了2次拷贝
Person p;
p.SetGender(parse_gender(1));
perfecttt 2009-11-19
  • 打赏
  • 举报
回复
return a;是局部变量a已经消失了,会产生一个零时变量,你引用的是临时变量的地址。详细内容参考c++ prime plus
na2650945 2009-11-19
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 macrojj 的回复:]
  cout < <"the address of r " < <&r < <endl;
  cout < <"the address of temp " < <&fun() < <endl;

调用第二次的时候 产生了新的临时对象,当时位置就不一样啦

而且r已经是一个临时对象的拷贝了。

[/Quote]
正解。
ele7enjr 2009-11-19
  • 打赏
  • 举报
回复
&fun()是否表示fun()函数返回的临时对象的地址?


哪里有&fun()????函数的地址是函数名表示
sj13426074890 2009-11-19
  • 打赏
  • 举报
回复
你的结贴率是0.00%,要养成结贴的好习惯
加载更多回复(6)

64,676

社区成员

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

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