1. ホーム
  2. c++

[解決済み] なぜ、コピーして移動するのか?

2022-12-25 10:02:28

質問

私は、誰かがオブジェクトをコピーし、その後それをクラスのデータメンバに移動することに決めたコードをどこかで見かけました。私は、移動の全体的なポイントはコピーを避けることであると考えていたので、これは私を混乱させました。以下はその例です。

struct S
{
    S(std::string str) : data(std::move(str))
    {}
};

以下は私の質問です。

  • なぜ私たちは str ?
  • 特に以下のようなことを考えると、コピーは高価になるのではないでしょうか? std::string ?
  • 作者がコピー→ムーブと判断した理由は何でしょう?
  • いつ自分でこれを行うべきでしょうか?

どのように解決するのですか?

質問に答える前に、あなたが誤解しているようなことが 1 つあります。C++11 での値による取得は、常にコピーを意味するわけではありません。rvalue が渡された場合、それは 移動 (実行可能な移動コンストラクタが存在する場合) となり、コピーされることはありません。また std::string には移動コンストラクタがあります。

C++03 と異なり、C++11 では、以下で説明する理由により、パラメータを値で受け取ることが慣用的であることがよくあります。また、以下を参照してください。 StackOverflow のこの Q&A も参照してください。 を参照してください。

へのrvalue-referenceを取らないのはなぜでしょうか? str ?

のように、lvalueを渡すことができなくなるからです。

std::string s = "Hello";
S obj(s); // s is an lvalue, this won't compile!

もし S が rvalue を受け取るコンストラクタだけを持っていた場合、上記はコンパイルされないでしょう。

特に次のようなものがあると、コピーは高価になりませんか? std::string ?

rvalueを渡すと、それは に移動します。 になります。 str に、そしてそれは最終的には data . コピーは行われない。一方,lvalueを渡した場合,そのlvalueは コピーされる にコピーされます。 str に移動し、さらに data .

まとめると、rvaluesは2回、lvaluesは1回コピーして1回移動するということですね。

作者がコピー→ムーブと判断した理由は何でしょうか?

まず第一に、上に述べたように、最初のものは必ずしもコピーではない。そしてこれは、答えは「"」である。 なぜなら、それは効率的だからです(moves of std::string オブジェクトの移動は安価である)、そしてシンプルであるため "です。

移動が安価であるという仮定の下では (ここでは SSO を無視します)、この設計の全体的な効率を考慮する場合、移動は実質的に無視することができます。そうすると、lvalue に対して 1 つのコピーがあります (lvalue 参照を const へのl値の参照を受け入れた場合のように)、r値のコピーはなく、(一方 const ).

これは、値で取ることは、lvalueの参照で取ることと同じであることを意味します。 const を参照するのと同じであり、rvalueが提供される場合はより良いということです。

追伸: いくつかの文脈を提供するために、私は次のように考えています。 これはQ&A を指していると思います。