为什么我应该按值返回一些东西,因为C++具有const引用?

Avi*_*ohn 19 c++ const reference function

考虑这个功能:

Thing func(){
    return something;
}
Run Code Online (Sandbox Code Playgroud)

每次调用此函数时,都会生成一个副本something并传递给调用者.

我的问题是,为什么不这样做(每次我想按价值归还)?

const Thing& func(){
    return something;
}
Run Code Online (Sandbox Code Playgroud)

这样,我们就没有冒充无法复制的风险something.如果客户端只需要"读取" something而不是"写入"它,那么const引用就可以完全实现.如果客户端确实需要副本,它可以简单地将const引用分配给变量,例如:

Thing thing = func(); // the object is passed by const reference, and then copied.
Run Code Online (Sandbox Code Playgroud)

那么,有没有理由简单地按价值回报?

顺便说一句,并不是因为我非常关心优化,只是因为我没有理由单纯地通过价值来回报.


跟进问题:阅读答案,我知道每种方法都有利弊.有违约吗?例如"默认按值返回"?或者它纯粹基于具体案例?

Mar*_* A. 25

因为如果您的对象(无论出于何种原因)是在被调用函数的堆栈上创建的,则返回并使用对它的引用是未定义的行为.

通过返回值,编译器有时可以优化返回,并且没有危险的悬空引用.使用C++ 11和移动语义,这将达到一个新的水平.

说"通过引用而不是通过值返回总是更好"是不合理的,每个使用一个的情况都必须单独考虑.

  • @AvivCohn通过不再在范围内的堆栈对象的引用访问内存是未定义的行为,一个无法在结果上信任的无效操作 (6认同)
  • @AvivCohn:如果它是静态的,那就有意义了.如果它是自动的,那么返回对它的引用总是一个错误. (4认同)
  • @AvivCohn我会分别考虑每个案例,也取决于你的代码的语义.无论如何:`-Wreturn-stack-address`,AFAIK标准并没有强制要求发出警告.但是,当有人这样做时总是很好. (2认同)

Col*_*mbo 8

那么,有没有理由简单地按价值回报?

是.例如,如果要返回函数局部变量.

int compute(int a, int b)
{
    int result;
    // a lot of magic
    return result;
}
Run Code Online (Sandbox Code Playgroud)

如果该函数要返回result任何类型的引用,那么它将是一个悬空的引用.

除此之外,可以使用copy elision优化返回具有"按值"类类型的函数局部变量 - 优化的名称是NRVO.如果该优化不适用,新引入的移动语义可能(尽管你应该只依赖于复制省略,它的效果非常好).在这种情况下,没有动机返回参考.

此外,如果您希望保密,则不希望返回引用.为什么要在公共成员函数中返回const引用到私有成员变量?它表示成员变量存在,呼叫站点不必知道的信息.还要考虑线程安全性:如果在return-statement 之后另一个线程正在修改同一个对象,则通过引用返回变量可能会导致数据争用.


或者它纯粹基于具体案例?

大多数情况下,您将按值返回,特别是对于非成员函数.成员函数可能会返回对成员*的引用,但几乎没有非成员函数返回引用的情况.只有当您知道自己需要(以及您正在做什么)时,才应该返回引用.

*而且只有他们真的需要.


Mik*_*our 6

如果要返回非静态局部变量,则必须按值返回,因为它将在函数返回时被销毁,从而使对它的任何引用无效.在这种情况下,副本通常可以由移动替换,或者完全省略.

如果你要回归一些东西,那么你是对的; 返回引用通常更好,让调用者决定是否应该复制它.但是可能还有其他原因,比如线程安全,更喜欢按值返回,即使这样:通过返回副本,读者无法访问持久对象,而另一个线程可能正在修改它.