返回const引用是否更有效

时间:2008-11-09 10:06:39

标签: c++ performance

E.g。

其中最好的是:

std::string f() {} 

const std::string& f() {}

3 个答案:

答案 0 :(得分:33)

函数永远不应该返回对本地对象/变量的引用,因为这些对象超出了作用域并在函数返回时被销毁。

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

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

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

即将推出的C ++ 0x标准,部分在gnu gcc-4.3中提供,引入了可用于区分左值和右值参考的右值参考[&amp;&amp;]。通过这种方式,可以实现移动构造函数,可以有效地返回一个对象,部分避免了复制构造函数和临时构造函数的破坏。

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

移动构造函数具有以下签名:

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

并且它应该取得传递对象的内部所有权,使后者处于默认状态。通过这样做,避免了内部的副本,并使临时的破坏变得容易。典型的功能工厂将具有以下形式:

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

std :: move()返回对象的右值引用。最后但同样重要的是,移动构造函数允许非可复制对象的rvalue引用返回。

答案 1 :(得分:16)

我想补充Nicola的优秀答案。是的,您必须永远不要返回悬空引用(例如,引用局部变量),但是,在这些情况下,有三种有用的方法可以提高性能:

  1. 返回值优化(RVO):按值返回,但只通过一个return语句消除复制,该语句在现场创建返回值。以下是使用RVO的示例:How can I tokenize a C++ string?

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

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

  4. 顺便说一句,我不能相信有关RVO和NRVO的信息;他们直接来自Scott Meyers的More Effective C++。由于我现在没有这本书,所以我的描述中的任何错误都是我的,而不是Scott的。 : - )

答案 2 :(得分:2)

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

如果在函数返回时返回仍在范围内的实例的引用,那么它将更快,因为没有创建字符串的副本。

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