【问题标题】:C++: what is the advantage of references in this case?C++:在这种情况下,引用的优势是什么?
【发布时间】:2015-10-20 06:31:54
【问题描述】:

我有两段代码:

int f1(int b)
{
   return b;
}

int & f2(int b)
{
   return b;
}

这些功能有什么区别?我知道第二个返回一个引用,但是由于我可以以相同的方式使用这两个函数,有什么区别?

编辑:这个功能更好吗?

int && f2(int b)
{
   return b;
}

什么时候应该使用返回引用的函数?

Edit2:那我什么时候应该使用返回右值引用的函数呢?

【问题讨论】:

  • 第二个函数暴露了未定义的行为。
  • since I can use both functions in the same way
  • int && 将是一个移动操作。不是你想要的,也可能在语义上不正确。在这里阅读:stackoverflow.com/questions/4148341/…

标签: c++ function reference


【解决方案1】:

考虑一个包装数组的简单类,仅用于提供一个示例,说明 OP 可以使用返回的引用做什么。

class example
{
private:
    int array[]= {1,2,3,4,5,6,7,8,9,0};
public:
    int get(int index)
    {
        return array[index];
    }
    int & get2(int index)
    {
        return array[index];
    }
}

现在我们有一个示例,它不会进入未定义行为的荒地,并且可以向您展示这个完全武装和可操作的参考的力量。

说我们有

example x;

我们可以调用任一 get 函数来检索值

int val1 = x.get(1);
int val2 = x.get2(2)

但我们也可以

x.get2(3) = 30;

因为 get2 返回了一个我们可以分配给它的引用并使分配生效。

如果您想在示例中添加索引运算符,这是非常宝贵的

int & operator[](int index)
{
    return array[index];
}

因为它允许预期的数组行为

int val = x[5];
x[6] = 10;

编辑

Tony D 提出了另一个重要特征。返回一个引用返回 by 引用。除了允许修改返回的对象之外,这不会复制并节省复制所消耗的任何精力。对于整数的示例情况,这是没有实际意义的。传递整数和对整数的引用的成本将相同或非常接近以至于无关紧要。对于可能需要大量工作来复制的更大、更复杂的对象或不能或不应该复制的对象,情况并非如此。

BigFreakingObject & getBigFreakingObject();

将允许调用者对BigFreakingObject 进行操作,而不会产生复制它的成本。然而,这会将钥匙交给王国,并允许调用者对BigFreakingObject 执行任何BigFreakingObject 的权限允许的操作,这可能与BigFreakingObject 的所有者的要求相冲突。

使用

将引用声明为 const
const BigFreakingObject & getBigFreakingObject();

BigFreakingObject const & getBigFreakingObject();

将提供对BigFreakingObject 的引用,但不允许调用者修改其状态,从而保护BigFreakingObject 的所有者免受任何令人不快的意外。

更多详情,read up on Const Correctness

【讨论】:

  • 我明白了。但是你能告诉我这个表达式有什么问题吗:x.get1(3) = 30; ?为什么不会粘?如果数组不是私有的,我可以写 array[3] = 30 并且它会坚持。
  • get1 按值返回,因此它不返回数组 [3]。它返回数组 [3] 的副本。如果您尝试修改它,编译器会捕获并警告您,但如果编译器允许它,您将完成的只是更改副本的值。原件不会受到影响。
  • 对我来说,对 setter 和 getter 方法的最大补充是它们允许验证。是物体的自卫。例如,我可以在任一 get 方法中添加范围检查,如果 index 小于 0 或大于 9,则抛出异常。对于 setter,对象可以防止外部人员更改其状态,或者至少在他们收到通知时收到通知。状态改变。使用公共变量的对象没有这样的保护。
  • @user2738748 值得注意的是,函数也可以返回const 引用,这不允许修改引用的对象,但允许在不复制的情况下访问值:这样可以更有效当对象很大时,并且对于主动不可复制的对象(例如已删除的复制构造函数)是必需的。即使对于 const 引用,它们也只能在被引用对象的生命周期内使用(即,对 f2 函数参数的访问仍然会被破坏)。
  • @TonyD 谢谢。不敢相信我漏掉了这个细节。
【解决方案2】:
int f1(int b) {
   return b;
}

返回整数 b。

int & f2(int b) {
   return b;
}

返回对函数返回时销毁的整数 b 的引用。换句话说,您将 b 按值传递给函数,这意味着 b 在函数的堆栈帧中有一个地址。一旦函数返回,该函数的堆栈帧中的任何内容,包括您返回的引用的 b 都不再存在。所以,你不知道这个引用到底指的是什么,所以你不能使用它。

编辑:您编辑的功能并不好。这会更正确:

int& f2(int& b) {
   return b;
}

除非您遇到像@user4581301 给出的示例那样的情况,否则您永远不应该返回对在您返回的函数中创建的对象的引用,原因如上所述!

如果您想将一个对象传递给一个函数,并让该函数对该对象执行某些操作而不复制该对象,请执行以下操作:

void f2(int& b) {
    ... do stuff to b
}

【讨论】:

  • 当函数是类的成员并返回对也是类成员的字段的引用时怎么样?
  • 您的示例具有返回对修改后引用的引用的函数并非完全没有意义。 ostream& operator
  • 谢谢。我将其编辑为指向@user4581301 的示例,这是一个很好的示例!
【解决方案3】:

在...

int & f2(int b)
{
   return b;
}

...参数b 是调用者提供的值的自动(堆栈托管)副本:当f2 返回时,堆栈空间被回收。当返回 int& 时,您将返回对 f2b 变量的引用,即使它的内存可供重用。如果您尝试使用返回的引用访问该值,则您的行为未定义。

【讨论】:

    猜你喜欢
    • 2014-03-17
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    • 2017-03-28
    • 2016-08-26
    • 1970-01-01
    • 2016-05-12
    相关资源
    最近更新 更多