3

次のコードを検討してください。

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
}

これらの実装の結果を説明し、ローカル オブジェクトのメンバーを返す最も効果的な方法を示してください。

4

2 に答える 2

3

余分なコピーを避ける方法はたくさんありますが、コードに近いものは私見です:

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
}

同じことは、戻りオブジェクトを構築する move によって達成できます

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); 
}
于 2015-07-20T08:31:34.313 に答える
1

この質問に対する答えだと思いますなぜここでコピーコンストラクターが省略されていないのですか? あなたの質問に答えるのに本当に役に立ちます。あなたの例ではコピー省略は使用されていません

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

この要件は満たされていないため ( http://en.cppreference.com/w/cpp/language/copy_elision ):

return ステートメントの式は、自動保存期間を持つ不揮発性オブジェクトの名前であり、関数の戻り値の型と同じ型 (トップレベルの cv 修飾を無視) を持つ場合、コピー/移動は省略されます

あなたの例では、Bar は自動保存期間を持つ変数ですが、Foo が返されます。Bar クラスを変更すると、コンパイラはコピー省略を使用して開始します。

#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()
于 2015-07-20T15:50:45.370 に答える