以下代码Value r = foo(i)
是r
引用还是副本?
Value foo(int i) {
return Value::New(i);
}
Value bar(Arg x) {
// should I use Value& r = foo(x.getIndex());
Value r = foo(x.getIndex());
x.close();
return r;
}
我测试了
#include <stdio.h>
using namespace std;
class Value {
public:
Value() {
printf("construct\n");
}
};
Value foo(){
Value a;
return a;
}
Value bar() {
Value b = foo();
return b;
}
int main(){
Value c = bar();
}
仅构建1次。
答案 0 :(得分:2)
取决于。如果Value
typedef
为某个引用类型(例如int&
),那么是,foo
将是引用。否则没有。但是,正如Paolo所指出的,Value
具有成员函数New
,因此不能是引用类型。因此,您通过副本传递/返回Value
,而不是通过引用。
发布编辑:您没有看到多次打印字符串消息的原因很简单:它仅在调用默认ctor时打印。实现一个实际的复制文件,每次复制Value
时,您会看到更多邮件。
答案 1 :(得分:0)
复制。您会注意到&
符号的引用。
真正的问题是foo
返回的内容。如果它返回一个引用 - 使用引用是有意义的,否则如果它返回一个副本(即:返回类型是Value
,而不是Value&
),你只需引用一个复制,那么重点是什么(你可能会收到编译器警告或错误)?
答案 2 :(得分:0)
这是副本。此外,您不能在那里使用引用(如在注释行中),因为foo
的返回值存储在临时值中并在行尾被破坏,从而创建悬空引用。
答案 3 :(得分:0)
复制,因为foo(int)
未返回引用。
答案 4 :(得分:0)
这是一个副本有两个原因。第一个,正如其他人指出的那样,foo返回Value
的副本,即它不会返回Value &
。
第二个原因是这种(误导性)语法
Value r = foo(x.getIndex());
与赋值运算符没有任何关系,它实际上等同于:
Value r( foo( x.getIndex() ) );
类Value的新对象是使用另一个类Value实例构建的,因此调用了复制构造函数。
关于源代码中的问题:
Value bar(Arg x) {
// should I use Value& r = foo(x.getIndex());
Value r = foo(x.getIndex());
x.close();
return r;
}
不,您不应该使用Value&
,因为为了保持有效,您应该将bar的返回值更改为Value&
,并且您不能返回对该对象的引用将在bar()
函数结束时结束它的生命。
希望这有帮助。
答案 5 :(得分:0)
仅构建1次
因为标准明确允许编译器优化复制构造(即使它有副作用)。编译器可以使用RVO
和NRVO
轻松优化您的代码。这基本上允许编译器在目标处构造一次对象(因此您看不到副本)。
它的副本
函数foo()返回类型Value
Value foo(int i)
如果要返回对value类型对象的引用,则需要在函数签名中指明:
Value & fooRef(int i)
// ^^^ Notice the & symbol
变量'r'也是一个对象。所以即使你为它分配一个引用。然后它会复制返回的原始对象。
Value rv = fooRef(1); // fooRef() returns a reference to an object.
// But here we make a copy into rv
Value& rf = fooRef(1); // fooRef() returns a reference.
// rf is a reference and keeps a reference to the object returned by
// fooRef()