如何返回本地对象的成员

时间:2015-07-20 06:48:58

标签: c++ c++11 move-semantics rvo

请考虑以下代码:

struct Foo
{
    Foo() { cout << "Foo()\n"; }
    ~Foo() { cout << "~Foo()\n"; }
    Foo(Foo&) { cout << "Foo(Foo&)\n"; }
    Foo(Foo&&) { cout << "Foo(Foo&&)\n"; }

    int d;
};

struct Bar
{
    Foo bigData;
    void workOnBigData() { /*...*/ }
}

Foo getBigData()
{
    Bar b;
    b.workOnBigData();
    return b.bigData;
}

在复制椭圆/移动语义方面实现getBigData()的最佳方法是什么?在此实现中,似乎不允许编译器移动bigData。我测试了以下功能:

Foo f()
{
    Foo foo;
    return foo;  // RVO
}

Foo g()
{
    Bar b;
    return b.bigData;  // Copy
}

Foo h()
{
    Bar b;
    auto r = move(b.bigData);
    return r;  // Move
}

您能否解释这些实现的结果,并显示返回本地对象成员的最有效方法。

2 个答案:

答案 0 :(得分:3)

有很多方法可以避免额外的副本,更接近你的代码的是imho:

Foo getBigData()
{
    Foo ret; // do a cheap initialization
    Bar b;
    b.workOnBigData();

    std::swap(ret, b.bigData); // 'steal' the member here

    return ret; // NRVO can apply
}

通过移动构造返回对象

可以实现同样的目的
Foo getBigData()
{
    Bar b;
    b.workOnBigData();     
    Foo ret(std::move(b.bigData)); // these two lines are equivalent to
    return ret;                    // return std::move(b.bigData); 
}

答案 1 :(得分:1)

我认为这个问题Why isn't the copy constructor elided here?的答案在回答你的问题时非常有用。您的示例中未使用复制省略

Foo getBigData()
{
    Bar b;
    b.workOnBigData();
    return b.bigData;
}

因为这个要求没有完整填写(http://en.cppreference.com/w/cpp/language/copy_elision):

  

return语句的表达式是非易失性对象的名称   有自动存储时间......   并且具有相同的类型(忽略顶级cv资格)   函数的返回类型,然后省略复制/移动

在您的示例中,Bar是一个具有自动存储持续时间但是返回Foo的变量。如果更改Bar类,编译器将开始使用copy elision:

#include <iostream>
#include <typeinfo>

using namespace std;

struct Foo
{
  Foo() { cout << "Foo()\n"; }
  ~Foo() { cout << "~Foo()\n"; }
  Foo(const Foo&) { cout << "Foo(Foo&)\n"; }
  Foo(Foo&&) { cout << "Foo(Foo&&)\n"; }

  int d;
};

struct Bar
{
  Foo bigData;
  void workOnBigData() { /*...*/ }
};

struct Bar2
{
  void workOnBigData(Foo&) { /*...*/ }
};

Foo getBigData()
{
    Bar b;
    b.workOnBigData();
    return b.bigData;
}

Foo getBigData2()
{
    Foo f;
    Bar2 b;
    b.workOnBigData(f);
    return f;
}

int main()
{
  {
    Foo f = getBigData();
  }
 cout << "---" << endl;

  {
    Foo f = getBigData2();
  }
}

#include <iostream>
#include <typeinfo>

using namespace std;

struct Foo
{
  Foo() { cout << "Foo()\n"; }
  ~Foo() { cout << "~Foo()\n"; }
  Foo(const Foo&) { cout << "Foo(Foo&)\n"; }
  Foo(Foo&&) { cout << "Foo(Foo&&)\n"; }

  int d;
};

struct Bar
{
  Foo bigData;
  void workOnBigData() { /*...*/ }
};

struct Bar2
{
  void workOnBigData(Foo&) { /*...*/ }
};

Foo getBigData()
{
    Bar b;
    b.workOnBigData();
    return b.bigData;
}

Foo getBigData2()
{
    Foo f;
    Bar2 b;
    b.workOnBigData(f);
    return f;
}

int main()
{
  {
    Foo f = getBigData();
  }
 cout << "---" << endl;

  {
    Foo f = getBigData2();
  }
}

这是它输出的内容:

$ ./a.out     
Foo()
Foo(Foo&)
~Foo()
~Foo()
---
Foo()
~Foo()