3

コンテナー ライブラリで次の最適化を達成しようとしています。

  • 左辺値参照要素を挿入するときは、それを内部ストレージにコピーします。
  • ただし、右辺値参照要素を挿入するときは、サポートされている場合は移動します。

最適化は、たとえば、含まれる要素の型が のような場合に役立つはずですstd::vector。可能であれば移動すると、大幅な速度向上が得られます。

ただし、これまでのところ、このための作業スキームを考案することはできませんでした。私のコンテナーは非常に複雑なので、insert()コードを何度も複製することはできません。サイズが大きいためです。私はすべての「実際の」コードをいくつかの内部ヘルパーに保持したいと考えていますdo_insert()(テンプレート化されている可能性があります) insert()

これに対する私の最善の策のコード(もちろん、実際には何もしないプロトタイプ):

#include <iostream>
#include <utility>

struct element
{
  element () { };
  element (element&&) { std::cerr << "moving\n"; }
};

struct container
{
  void  insert (const element& value)
  {  do_insert (value);  }

  void  insert (element&& value)
  {  do_insert (std::move (value));  }

private:
  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (arg);  }
};

int
main ()
{
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
  }

  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}

ただし、これは少なくとも GCC 4.4 および 4.5 では機能しません。stderr に「moving」と表示されることはありません。それとも、私が達成したいことは不可能であり、それがemplace()そもそものような機能が存在する理由ですか?

4

3 に答える 3

1

私はあなたが議論を転送する必要があるかもしれないと思います:

  template <typename Arg>
  void  do_insert (Arg&& arg)
  {  element  x (std::forward<Arg>(arg));  }

完全なコード:

#include <iostream>
#include <utility>

struct element
{
  element () { };
  element (const element&) { std::cerr << "copying\n"; }
  element (element&&) { std::cerr << "moving\n"; }
};

struct container
{
  void  insert (const element& value)
  {  do_insert (value);  }

  void  insert (element&& value)
  {  do_insert (std::move(value));  }

private:
  template <typename Arg>
  void  do_insert (Arg&& arg)
  {  element  x (std::forward<Arg>(arg));  }
};

int
main ()
{
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
  }
  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}

あなたが探すかもし​​れないキーワードは「完璧な転送」です。

于 2010-04-24T14:59:19.797 に答える
0

あなたのSTL実装(またはオンラインで読むことができるはずのGNU)で行われている方法をコピーすることをお勧めします。

しかし

  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (move(arg));  }

トリックを行うかもしれません。

この機能は標準ライブラリとは別のものemplaceであり、標準ライブラリで動作することは正しいです。

EDITいくつかの変更を加えて発見しました

  • 2 つのメッセージを取得する場合、挿入ごとに 1 つずつあります
  • 2回目の挿入は問題ないようです
  • 最初のものはスプリアスを生成しますmoveが、元のオブジェクトは移動されませんでした。そのため、移動中の一時ファイルを見つけることに集中してください。これは実際にはそれほど悪いことではありません。

.

#include <iostream>
#include <utility>

struct element
{
  element () : moved(false) { };
  element (element&&) { moved = true; std::cerr << "moving\n"; }
  bool moved;
};

struct container
{
  void  insert (const element& value)
  {  do_insert (value);  }

  void  insert (element&& value)
  {  do_insert (std::move (value));  }

private:
  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (std::move(arg));  }
};

int
main ()
{
  std::cerr << "try 1\n";
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
    std::cerr << x.moved << "\n";
  }

  std::cerr << "try 2\n";
  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}
于 2010-04-24T15:09:52.320 に答える
0

なぜこれが機能し、他のコードが機能しないのかを理解しているとは言えませんが、これはうまくいくようです (Potatoswatter からのヒントのおかげで作成されました)。

#include <iostream>
#include <utility>

struct element
{
  element () { };
  element (const element&) { std::cerr << "copying\n"; }
  element (element&&) { std::cerr << "moving\n"; }
};

struct container
{
  void  insert (const element& value)
  {  do_insert <const element&> (value);  }

  void  insert (element&& value)
  {  do_insert <element&&> (std::forward <element&&> (value));  }

private:
  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (std::forward <Arg> (arg));  }
};

int
main ()
{
  std::cerr << "1\n";
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
  }

  std::cerr << "2\n";
  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}

GCC 4.4 と 4.5 の両方で次の出力が得られます。

1
copying
2
moving
于 2010-04-24T16:03:36.680 に答える