返回引用变量的函数?

4

在C++中,

function() = 10;

如果函数通过引用返回一个变量,那么这个方法是可行的,对吗?

能否有人详细解释一下这个问题?


1
如果 function() 以值形式返回用户自定义类型的 rvalue,它也可以正常工作 - 这类似于对非 const 结构体 / 类型 / 联合 rvalue 进行的 function().operator=(10) 完全合法的调用。 - Pavel Minaev
@Pavel:甚至可以是一个const值,只要你够古怪,愿意写一个const operator=。 - bcat
7个回答

15

首先考虑这段代码

int *function();
...
*function() = 10;

看起来很相似,不是吗?在这个例子中,function 返回一个指向 int 的指针,您可以通过对其应用一元 * 运算符以上述方式使用它。

现在,在这个特定的上下文中,您可以将引用视为“伪装成指针”的指针。也就是说,引用是一个“指针”,只是您不需要对其应用 * 运算符。

int &function();
...
function() = 10;

一般来说,将引用与指针等同并不是一个很好的想法,但对于这个特定的解释,它非常有效。


1
在我之前进来的人加一分。伟大的思想都是如此 :) - Binary Worrier
做得好,使用了一个不完全正确但仍然合适的比喻来清晰地解释它,同时也指出了通常使用不完全正确的比喻的危险 :) - Pavel Minaev

7
考虑下面的代码,MyFunction返回一个指向int的指针,然后你可以给这个int赋值。
int  *i;
i = MyFunction();
*i = 10;

你跟上了吗?

现在简化一下

*(MyFunction()) = 10;

它与第一个代码块完全相同。

你可以将引用看作始终被解除引用的指针。因此,如果我的函数返回一个 int 的引用而不是指针,则第一个代码块将变为:

int  &i;
i = MyFunction();
i = 10;

第二个则会变成

MyFunction() = 10;

你还在跟我吗?

2
通过一些实验,您可以确定这是否有效。考虑以下示例:
class foo {
    private:
        int _val;
    public:
        foo() { _val = 0; }
        int& get() { return _val; }
        void print() { printf("val: %d\n", _val); }
};

int main(void) {
    foo bar;
    bar.print();
    bar.get() = 10;
    bar.print();
}

它的输出结果为:

val: 0
val: 10

所以,确实可以返回引用。请注意,被引用的变量可能会超出范围,然后调用者可能会得到垃圾结果(就像解引用已经超出范围的对象指针一样)。因此,这将是不好的:

int& get() {
    int myval = _val;
    return myval;
}

1
一个你没有问到的问题。
但是你为什么想要这样做呢?
想想std::vector(我正在将原则扩展到方法)。
在这里,你有方法'operator[]()'它返回对内部成员的引用。
然后就可以实现以下操作:
std::vector<int>  x(20,1);
x[5] = 10;

// This is quivalent to:
x.operator[](5) = 10;

// So this is just a function (method) call:
x.function(5) = 10;

1
这个问题的答案与rvalue语义和lvalue语义有关。在C++中,每个值都是lvalue或rvalue。Lvalues是存储在可寻址内存位置中的值,这意味着它们是可分配的(当然,假设它们是非const的)。Rvalue基本上是其他任何东西,例如文字常量或不可寻址的临时值。
因此,返回非const引用的函数是一个lvalue。但是,按值返回的函数将是一个rvalue表达式,因为它返回一个不可寻址的临时值,因此不能被分配。
请参见wikipedia条目,以获取更详细的解释和示例。

0
警告一句,当返回一个引用时:请注意你要返回的对象的生命周期。以下示例是错误的:
int &function()
{
    int x;
    // BAD CODE!
    return x;
}
...
function() = 10;

x在function之外不存在,也没有任何对它的引用。为了从函数中返回一个引用,被引用的对象必须至少持续和引用一样长。在上面的例子中,x需要被声明为静态变量。其他可能性包括将x作为全局变量、将function作为类成员函数并返回对类成员变量的引用、或者在堆上分配x并返回对其的引用(尽管这在释放方面会变得棘手)。


我不明白为什么你认为这只是针对非const引用的特定情况。在这个特定的例子中,返回任何类型的引用(无论是const还是非const)都会导致同样的问题。 - AnT stands with Russia
嗯,是的,谢谢 - 今天有点恍惚。我提到了non-const,因为你无论如何都不能修改const引用,但在我说的其他事情的背景下,这并不重要。 - Eclipse

0
正如其他人所指出的,函数可以返回成员变量的引用,但需要注意:这个函数不应该是类接口的一部分。一旦你提供了一个返回类内部引用的函数,你就失去了对它们的控制。 如果你还没有读过《Effective C++》,那就赶紧去读吧。 该书的第29条建议“避免返回内部数据的‘句柄’”,并详细解释了为什么需要避免这种做法。

如何在不违反规则的情况下重载operator[]运算符? - Fred
很好的观点,弗雷德。但[](非const)的语义表明该运算符是mutator。通常用于这样的情况,即x[5] = 10; 但它当然也可以被滥用,例如int&vectorElement = x [5]; (稍后再使用...疼...) 但这就是您为方便而支付的代价。 - BostonLogan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接