6

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

#include <vector>
#include <boost/noncopyable.hpp>

struct A : private boost::noncopyable
{
  A(int num, const std::string& name)
    : num(num),
      name(name)
  {
  }

  A(A&& other)
    : num(other.num),
      name(std::move(other.name))
  {
  }

  int num;
  std::string name;
};

std::vector<A> getVec()
{
  std::vector<A> vec;
  vec.emplace_back(A(3, "foo"));
  // vec.emplace_back(3, "foo"); not available yet in VS10?

  return vec; // error, copy ctor inaccessible
}

int main ( int argc, char* argv[] )
{
  // should call std::vector::vector(std::vector&& other)
  std::vector<A> vec = getVec();

  return 0;
}

これは VS2010 ではコンパイルされません。これは明らかにAコピーできないためです。したがって、関数から a を返すことはできません。noncopyablestd::vector<A>std::vector<A>

しかし、RVO の概念を考えると、この種のことが不可能であるというのは、私には正しくありません。ここで戻り値の最適化を適用すると、コピーの作成を省略でき、 への呼び出しgetVec()が有効になります。

では、これを行う適切な方法は何でしょうか? これはVS2010 / C++ 11でまったく可能ですか?

4

2 に答える 2

11

return vec;がコンパイルされない場合、VS2010 は移動セマンティクスをまだ完全にはサポートしていません。通常、関数から返された場合、自動変数は暗黙的に移動されます。一時的な回避策として使用し、将来的return std::move(vec);に を取り除くために頭の中でメモしておいてくださいstd::move

完全な説明は、この FAQ の回答の「機能からの移動」という見出しの下にあります。

また、引数が 2 つのコンストラクターは、const への参照によって渡される文字列引数のコピーを作成します。代わりに引数を値で取り、それをメンバーに移動することをお勧めします。

A(int num, std::string name) : num(num), name(std::move(name)) { }

このようにして、必要なコピーの数を最小限に抑えます。速度が欲しいですか?を参照してください。詳細については、値渡しを参照してください。

また、移動コンストラクターは特別なことを何もしないので、次のことができdefaultます。

A(A&& other) = default;

これにより、変更に直面してもより堅牢になります。あなたが書いていないコードにバグが隠れることはめったにありません:)

于 2012-07-23T08:21:41.023 に答える
6

しかし、RVO の概念を考えると、この種のことが不可能であるというのは、私には正しくありません。

名前付きの戻り値の最適化などの一般的な用語であるエリシオンは、最適化です。必須ではありませ。仕様では許可されていますが、許可されている場合でも、実装に強制することはありません。

そのため、省略を許可するコンパイラと許可しないコンパイラ間の一貫性を確保するために、操作によって省略が許可されている場合でも、コンパイラは、コードの現在の状態を考慮して、省略されているコピー/移動が可能であることを確認する必要があります。そのため、コピー/移動コンストラクターにアクセスできない場合、コンパイラーが実際に呼び出さなくても操作は失敗します。

この場合、Visual Studio 2010 はこの点で混乱しているようです。return vec;から移動する必要があることを認識しvecます。ただし、VS2010 のstd::vector実装では、移動するには移動代入演算子が必要なようです。それがなければ、コピーを試みます。

于 2012-07-23T08:07:20.490 に答える