为了明确我的问题,我举了以下例子:
#include <iostream>
class Abc
{
public:
int a;
int b;
int c;
};
class Abc fun1()
{
Abc obj;
obj.a = 3;
obj.b = 4;
obj.c = 5;
return obj;
};
int main ()
{
Abc obj1;
obj1 = fun1();
std::cout<<"obj1 address is "<<&obj1<<std::endl;
Abc &obj11 = fun1();
std::cout<<"obj11 address is "<<&obj11<<std::endl;
return 0;
}
正如您所看到的,函数的返回值是一个类对象,当您调用此函数来创建类对象时,您可以使用类对象obj1
或类引用{{1 }}。对我来说,他们是一样的,我想知道他们之间的区别是什么以及鼓励哪种做法。
修改 它可以在Visual Studio 2010上编译。
答案 0 :(得分:1)
obj1 = fun1();
fun1()创建一个对象,然后obj1 COPIES 它的内容。所以你有两个对象,一个是匿名的,你不能再使用了,而obj1就是它的精确副本。
在
行Abc &obj11 = fun1();
你抓住了对象fun1()创建了哪个引用。现在你只有 ONE 对象,被一个引用抓住了。
请注意A a
和A& a = b
不一样。 A a
在堆栈上创建一个对象。 A& a = b
不创建另一个对象,只是用引用“捕获”一个对象。
答案 1 :(得分:1)
Abc &obj11 = fun1();
此行使程序格式不正确; C ++规范禁止将临时值绑定到不是const
的引用。兼容的C ++编译器会发出此错误。据推测,您使用的是Microsoft Visual C ++编译器,众所周知,该编译器允许将临时绑定到非const
引用,与C ++规范相矛盾。
const Abc &obj11 = fun1();
此行格式正确,它会导致临时绑定到引用。
在任何情况下,当临时绑定到引用时,临时将延长其生命周期以匹配引用的生命周期,因此当引用超出范围时,临时也将被销毁。换句话说,就寿命语义而言,它等同于行Abc obj1 = fun1();
1 。如果您正在使用省略副本的编译器,则在两种情况下都将省略所有副本。如果没有删除副本,则参考案例将减少一份副本:
obj1
然后销毁。请注意,一个不错的优化编译器将完全优化所有副本以及参考细节,为您提出相同的装配输出。
(如果您有兴趣,请here is a test case稍微调整一下代码中的问题。请注意,除非禁用了复制省略,否则不会复制任何副本。)
1 请注意,这与您问题中的代码Abc obj1; obj1 = fun1();
不同。我故意改变它,因为你写的代码不能直接比较,因此比较它们没有多大意义。如果您将其重写为Abc obj1 = fun1();
,则可以比较两行,因为Abc obj1; obj1 = fun1();
涉及默认构造,然后是复制分配。