web-dev-qa-db-ja.com

値またはconst参照でコピーする必要があるパラメーターを渡す

私は基本的な(数学)ベクトルクラスを持っています。私の意見では、C++の演算子のオーバーロードの恩恵を受けています。ベクトルスカラー演算は、クラス自体の自己変更関数として定義されます。

class Vec3i {
  Vec3i& operator+=(int const n) {
    for (int i = 0; i < 3; ++i) {
      _data[i] += n;
    }
  }
  std::array<int, 3> _data;
};

そして非変更無料関数として。これらについては、ベクターを渡す際に2つのオプションを見ることができます。

// By value, meaning an implicit copy.
Vec3i operator+(Vec3i lhs, int const rhs) {
  return (lhs += rhs);
}

// By const reference, copying manually.
Vec3i operator+(Vec3i const& lhs, int const rhs) {
  auto result = lhs;
  return (result += rhs);
}

あるバリアントを他のバリアントよりも好む正当な理由はありますか?私はconstパラメーター(変更されないすべてのものをconst-ing)を使用することを好みますが、値によるバリアントは簡潔です。または、暗黙的にconstとして値による読み取りを開始する必要がありますか?

7
Kolja

古いC++(C++ 11より前)では、operator+の2つの実装に大きな違いはありません。オペレーターを呼び出すとき、またはオペレーター内で明示的なコピーを作成するときに、コピーコンストラクターが呼び出されます。
この場合、どちらを選択するかは、個人の好み/コーディングガイドラインの問題です。

C++ 11に移動コンストラクターが導入されたことで、値渡しのケースが有利になりました。これにより、オペレーターが呼び出されている内容に応じて、コピーコンストラクターまたは移動コンストラクターのいずれかを使用してパラメーターを構築できます。と。
Vec3iクラスの場合、違いはそれほど大きくありませんが、動的に割り当てられたリソースを維持するクラスがある場合、移動コンストラクタを適切に使用すると、アプリケーションに必要なメモリの量を大幅に減らすことができます。

これはおそらく少し意見が分かれますが、コードに同等の代替案が2つある場合、通常は「ノイズ」の少ない代替案を選択します。あなたの場合、最初の代替案に対する2番目の代替案の違いはonlyであり、追加の「ノイズ」-読みやすさを向上させない技術的なコードです。そのため、最初のバリアントを使用します。

または、暗黙的にconstとして値による読み取りを開始する必要があります

「値による」引数を持つ関数は、それが意図したものである場合は、副作用のないものとして読み取る必要があります。

2
Doc Brown

私は、テイクバイバリューアプローチを採用します。

たぶんこの場合、それはVec3iは安価にコピーできますが、一般に、これによりlhs値をrvalueからmoveコンストラクターを使用して構築できるため、オブジェクトのコピーが削除されます。

0
UldisK