C++ 返回const引用是否更有效

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/275795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:15:45  来源:igfitidea点击:

Is it more efficient to return a const reference

c++performance

提问by Chris Jester-Young

E.g.

例如

What's best out of these:

什么是最好的:

std::string f() {} 

or

或者

const std::string& f() {}

回答by Nicola Bonelli

A function should never returna reference to a local object/variable since such objects go out of the scope and get destroyed when the function returns.

函数不应返回对本地对象/变量的引用,因为此类对象超出范围并在函数返回时被销毁。

Differently, the function can return a const or non const reference to an object whose scope is not limited by the function context. Typical example is a custom operator<<:

不同的是,函数可以返回对范围不受函数上下文限制的对象的 const 或非 const 引用。典型的例子是一个自定义operator<<

std::ostream & operator<<(std::ostream &out, const object &obj)
{
   out << obj.data();
   return out;
}

Unfortunately, returning-by-value has its performance drawback. As Chris mentioned, returning an object by value involves the copy of a temporary object and its subsequent destruction. The copy takes place by means of either copy constructor or operator=. To avoid these inefficiencies, smart compilers may apply the RVO or the NRVO optimizations, but there are cases in which they can't -- multiple returns.

不幸的是,按值返回有其性能缺陷。正如 Chris 所提到的,按值返回对象涉及临时对象的副本及其随后的销毁。复制通过复制构造函数或operator=. 为了避免这些低效率,智能编译器可能会应用 RVO 或 NRVO 优化,但在某些情况下它们不能——多次返回。

The upcoming C++0x standard, partially available in gnu gcc-4.3, introduces the rvalue reference [&&] that can be used to distinguish a lvalue from a rvalue reference. By means of that, it's possible to implement the move constructor, useful to return an object partially avoiding the cost of copy constructor and the destructor of the temporary.

即将推出的 C++0x 标准(部分在 gnu gcc-4.3 中可用)引入了右值引用 [&&],可用于区分左值和右值引用。通过这种方式,可以实现移动构造函数,有助于返回一个对象,部分避免复制构造函数和临时析构函数的成本。

The move constructor is basically what Andrei envisioned some years ago in the article http://www.ddj.com/database/184403855suggested by Chris.

移动构造函数基本上是 Andrei 几年前在Chris 建议的文章http://www.ddj.com/database/184403855 中设想的。

A move constructorhas the following signature:

一个移动构造函数具有以下特征:

// move constructor
object(object && obj)
{}

and it's supposed to take the ownership of the internals of the passed object leaving the latter in a default state. By doing that, copies of internals are avoided and the destruction of the temporary made easy. A typical function factory will then have the following form:

并且它应该拥有传递对象的内部结构的所有权,使后者处于默认状态。通过这样做,可以避免内部结构的副本,并且可以轻松地销毁临时文件。典型的函数工厂将具有以下形式:

object factory()
{
    object obj;
    return std::move(obj);
}

The std::move()returns a rvalue reference from an object. Last but not least, move constructors allow the return-by-rvalue-reference of non-copyable objects.

所述std::move()返回来自物体的右值引用。最后但并非最不重要的一点是,移动构造函数允许不可复制对象的按右值引用返回。

回答by Chris Jester-Young

I would like to add to Nicola's excellent answer. Yes, you must never return a dangling reference (e.g., reference to a local variable), however, there are three useful ways to improve performance in those cases:

我想补充尼古拉的出色答案。是的,您绝不能返回悬空引用(例如,对局部变量的引用),但是,在这些情况下,有以下三种有用的方法可以提高性能:

  1. Return-value optimisation (RVO): You return by value, but eliminate copying by having only one returnstatement, which creates the return value on the spot. Here's an example of RVO being used: How can I tokenize a C++ string?

  2. Named return-value optimisation (NRVO): You return by value, and declare the return value variable first, at the top of the function. All returnstatements return that variable. With compilers that support NRVO, that variable is allocated in the return-value slot, and does not get copied upon return. e.g.,

    string
    foobar()
    {
        string result;
        // fill in "result"
        return result;
    }
    
  3. Use a shared_ptror the like as the return type; this necessitates creating your object on the heap, rather than the stack. This prevents dangling-reference problems while still not requiring the whole object to be copied, just the smart pointer.

  1. 返回值优化 (RVO):您按值返回,但通过只有一个return语句来消除复制,这会在现场创建返回值。这是使用 RVO 的示例:如何标记 C++ 字符串?

  2. 命名返回值优化 (NRVO):按值返回,并首先在函数顶部声明返回值变量。所有return语句都返回该变量。对于支持 NRVO 的编译器,该变量被分配在返回值槽中,并且在返回时不会被复制。例如,

    string
    foobar()
    {
        string result;
        // fill in "result"
        return result;
    }
    
  3. 使用 ashared_ptr等作为返回类型;这需要在堆上创建对象,而不是在堆栈上。这可以防止悬空引用问题,同时仍然不需要复制整个对象,只需要复制智能指针。

By the way, I can't take credit for the information about RVO and NRVO; they come straight out of Scott Meyers's More Effective C++. Since I don't have the book with me at the moment, any errors in my description are my doing, not Scott's. :-)

顺便说一句,我不能相信有关 RVO 和 NRVO 的信息;它们直接来自 Scott Meyers 的More Effective C++。由于我目前没有这本书,因此我描述中的任何错误都是我自己造成的,而不是 Scott 的。:-)

回答by OJ.

If you return a reference to a variable that is local to the function then you're going to end up with issues (depending on the compiler and its settings).

如果您返回对函数局部变量的引用,那么您最终会遇到问题(取决于编译器及其设置)。

If you return a reference to an instance that's still in scope when the function returns then it will be faster, as no copy of the string is being created.

如果在函数返回时返回对仍在作用域内的实例的引用,那么它会更快,因为不会创建字符串的副本。

So the latter is more efficient (technically) but may not function as expected depending on what you return a reference to.

所以后者更有效(技术上),但可能无法按预期运行,具体取决于您返回引用的内容。