这是副本吗?但为什么它像参考一样工作?

时间:2011-12-20 09:29:16

标签: c++

以下代码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次。

6 个答案:

答案 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次

因为标准明确允许编译器优化复制构造(即使它有副作用)。编译器可以使用RVONRVO轻松优化您的代码。这基本上允许编译器在目标处构造一次对象(因此您看不到副本)。

原始答案

它的副本

函数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()