1. ホーム
  2. c++

pass-by-valueとthen-moveの構成は悪いイディオムなのか?

2023-08-24 11:19:40

質問

C++ではmoveセマンティクスがあるため、最近では

void set_a(A a) { _a = std::move(a); }

その理由は、もし a が rvalue である場合、コピーは消去され、移動は 1 回だけとなるからです。

しかし、もし a が lvalue の場合はどうなるのでしょうか?コピー構築と移動代入が行われるようです(A に適切な移動代入演算子があると仮定しています)。オブジェクトにあまりにも多くのメンバ変数がある場合、移動の代入はコストがかかることがあります。

一方、もし私たちが

void set_a(const A& a) { _a = a; }

コピー代入は1つだけです。lvalueを渡す場合、この方法はpass-by-valueイディオムより好ましいと言えるでしょうか?

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

Expensive-to-move 型は、最近の C++ の使い方ではまれです。移動コストが気になる場合は、両方のオーバーロードを記述します。

void set_a(const A& a) { _a = a; }
void set_a(A&& a) { _a = std::move(a); }

またはパーフェクトフォワードのセッター。

template <typename T>
void set_a(T&& a) { _a = std::forward<T>(a); }

に暗黙のうちに変換できるものであれば何でも受け入れます。 decltype(_a) に暗黙的に変換できるものであれば、余分なコピーや移動は必要ありません。

lvalue から設定するときに余分な移動を必要とするにもかかわらず、このイディオムは 悪い というのも、(a) 大多数の型が一定時間の移動を提供し、(b) コピー アンド スワップは 1 行のコードで例外安全性とほぼ最適なパフォーマンスを提供するからです。