返回const引用是否更有效

12 c++ performance

例如

这些中最好的是:

std::string f() {} 
Run Code Online (Sandbox Code Playgroud)

要么

const std::string& f() {}
Run Code Online (Sandbox Code Playgroud)

Nic*_*lli 35

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

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

std::ostream & operator<<(std::ostream &out, const object &obj)
{
   out << obj.data();
   return out;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

// move constructor
object(object && obj)
{}
Run Code Online (Sandbox Code Playgroud)

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

object factory()
{
    object obj;
    return std::move(obj);
}
Run Code Online (Sandbox Code Playgroud)

std :: move()从对象返回一个右值引用.最后但并非最不重要的是,移动构造函数允许非可复制对象的rvalue引用返回.


Chr*_*ung 16

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

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

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

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

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


OJ.*_*OJ. 3

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

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

因此,后者(从技术上来说)更高效,但可能无法按预期运行,具体取决于您返回的引用的内容。