3

RVO に関するDave Abrahamsの記事と、SO に関する他のいくつかの Q/A ( 14043609、9293726、および10818278 ) を読みましたが、まだ質問があります。次のコードをコンパイルして実行すると、次の出力が得られます。

Address of v in func    0x7fffac6df620
Address of v.data in func       0x2081010
Address of v in main    0x7fffac6df690
Address of v.data in func       0x20811b0
9

私には、コピーが作成されているようです。関数から大きなオブジェクトを渡すにはどうすればよいですか? 明示的な構造を記述せずに 1 つ以上のオブジェクトを返したいことに注意してください。-O2 を指定して GCC 4.6.3 を使用しました。編集: 最初の 2 つの回答は、コンパイラに期待しすぎていることを示しています。同じように動作する main2 を追加しました。たとえば、出力されるアドレスが異なります。大きなオブジェクトを効率的に返すことが動機であることを強調したいと思います。

#include <iostream>
#include <vector>
#include <tuple>

std::tuple<std::vector<int>, double> func() {
  std::vector<int> v;
  v.reserve(100);
  for (int k=0;k!=100;k+=1)
    v.push_back(k);

  double a = 5.0;
  std::cout << "Address of v in func\t" << &v << std::endl;
  std::cout << "Address of v.data in func\t" << v.data() << std::endl;
  return make_tuple(v, a);
}

int main() {
  std::vector<int> v;
  double a;
  std::tie(v, a) = func();
  std::cout << "Address of v in main\t" << &v << std::endl;
  std::cout << "Address of v.data in func\t" << v.data() << std::endl;
  std::cout << v[9] << std::endl;
  return 0;
}


int main2() {
  auto tp = func();
  std::vector<int> & v = std::get<0>(tp);
  double & a = std::get<1>(tp);
  std::cout << "Address of v in main\t" << &v << std::endl;
  std::cout << "Address of v.data in func\t" << v.data() << std::endl;
  std::cout << v[9] << std::endl;
  return 0;
}
4

5 に答える 5

3

vとの両方aが で変数として宣言されているためmain()、削除するコピーはありません。ここで得られるのは、コピーの構築ではなく、コピーの代入です。これは次と同等です。

struct Foo {};

Foo foo() { return Foo(); }

int main()
{
  Foo f1;
  f1 = foo();  // no copy hence f1 is distinct from object returned
  Foo f2 = foo(); // We can get RVO here, returned object can be f2.
}
于 2013-03-13T13:18:18.787 に答える
0

回答ありがとうございます。ティモの答えが最も役に立ちました。これが、その答えを自分のスタイルに適応させた方法です。funcと の両方でボイラープレートが重複していることに注意してくださいmain。もちろん、誰かがそれを取り除く方法を知っていれば、それは素晴らしいことです!

#include <iostream>
#include <vector>
#include <tuple>

std::tuple<std::vector<int>, double> func() {
  std::tuple<std::vector<int>, double> tp;
  std::vector<int> & v = std::get<0>(tp);
  double & a = std::get<1>(tp);

  v.reserve(100);
  for (int k=0;k!=100;k+=1)
    v.push_back(k);

  a = 5.0;
  std::cout << "Address of v in func\t" << &v << std::endl;
  std::cout << "Address of v.data in func\t" << v.data() << std::endl;
  return tp;
}

int main() {
  std::tuple<std::vector<int>, double> tp = func();
  std::vector<int> & v = std::get<0>(tp);
  double & a = std::get<1>(tp);

  std::cout << "Address of v in main\t" << &v << std::endl;
  std::cout << "Address of v.data in func\t" << v.data() << std::endl;
  std::cout << v[9] << std::endl;

  (void)a;
  return 0;
}
于 2013-03-13T14:08:05.757 に答える