web-dev-qa-db-ja.com

C ++の戻り値、参照、const参照

戻り値、値への参照、および値へのconst参照の違いを説明できますか?

値:

Vector2D operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

非const参照:

Vector2D& operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

定数参照:

const Vector2D& operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

これの利点は何ですか?関数内で参照が指しているこの値を変更しないようにしたいので、関数に渡すconst参照の背後にある意味を理解しています。しかし、私はconst参照を返す意味に混乱しています。参照の返却が値の返却よりも優れている理由、およびconst参照の返却が非const参照の返却より優れている理由

37
Majak

変なものを書かない限り違いはありません

(v1 += v2) = v3;

前者の場合、割り当ては一時的なものになり、全体的な効果はv1 += v2になります。

2番目の場合、割り当てはv1に行われるため、全体的な効果はv1 = v3になります。

3番目の場合、割り当ては許可されません。このような奇妙さは間違いなく間違いであるため、これがおそらく最良の選択肢です。

参照を返すことが値を返すよりも優れているのはなぜですか?

潜在的にはより効率的です。オブジェクトのコピーを作成する必要はありません。

そして、なぜconst参照を返すのがnot-const参照を返すよりも良いのでしょうか?

上記の例のような奇妙さを防ぎますが、

v1 = (v2 += v3);

しかし、コメントで述べたように、それはあなたの型が組み込み型と同じ(ab)useの形式をサポートしていないことを意味します。

22
Mike Seymour

値:

値で返すとは、オブジェクトのコピーを返すことを意味します。これにより、クラスに要件が課されます(コピー可能または移動可能である必要があります)。これは、値によって返される一部のクラスのオブジェクトでは、コストがかかる可能性があることを意味します(RVOまたはNRVOが機能しないか、オフになっている場合)。また、これは、新しいオブジェクトが他のオブジェクトから独立しており(そのデザインに依存)、独自の値であることも意味します。これはおそらく、+、-、*などの多くのバイナリ演算子から返す必要があるものです。

非定数参照:

別のオブジェクトのエイリアスを本当に返します。エイリアスが非constの場合、エイリアスオブジェクトを変更できます。これは、通常、返されるオブジェクトを変更できるようにするために、プレフィックス++や-、*(逆参照)などの単項演算子から返す必要があるものです。

これは、ストリームに対してオーバーロードされたoperator >>およびoperator <<によって返されます。これにより、演算子の連鎖が可能になります。

cout << 5 << "is greater then" << 1 << endl;
cin >> myInt >> myFloat;

次のような通常のメソッドのチェーンを許可する場合は、* thisへの参照を返すこともできます。

object.run().printLastRunStatistics();

定数参照:

上記と同様ですが、エイリアスオブジェクトを変更することはできません。返されるオブジェクトのコピーに費用がかかる場合や、関数から戻った後にその存在を確認できる場合は、値で返す代わりに使用できます。

これは、通常の型がサポートする方法で複数の割り当てを許可するためにoperator =が通常返すものです。

a = b = c;

Operator =で使用される定数参照は、この種の使用を防止します(覚えている限り、標準タイプではサポートされていません)。

++(a = b);

通常の参照が使用された場合に許可されます。

10
Tomek

return-by-valuereturn-by-referenceの違いは、実行時に有効になります。

オブジェクトを値ごとに返すと、コピーコンストラクターが呼び出され、スタック上に一時インスタンスが作成されます。

オブジェクトを参照渡しすると、上記のすべてが実行されず、パフォーマンスが向上します。


return-by-referencereturn-by-constant-referenceの違いは、実行時の影響はなく、誤ったコードの記述から保護するためにあります。

たとえば、Vector2D& operator += (const Vector2D& vector)を使用すると、次のことができます。

_(x+=y)++_または_(x+=y).func()_ここで、funcはクラス_Vector2D_の非const関数です。

ただし、const Vector2D& operator += (const Vector2D& vector)を使用すると、このような同様の試みに対してコンパイラーはエラーを生成します。

5
barak manos

関数に引数を渡すのとまったく同じです。

オブジェクトのプロパティを返すときに、その外部で変更されないようにするには、const参照を返します。たとえば、オブジェクトに名前がある場合、次のメソッドconst std::string& get_name(){ return name; };を作成できます。これが最も最適な方法です。コピーオンリターンなしで、内部プロパティへの「読み取り専用」アクセスを許可します。

演算子をオーバーロードしている場合、変更可能なオブジェクトを返すことが期待されます。そうしないと、通常動作すると予想される特定の構文でエラーが発生します。奇妙な連鎖を試みるとき、それは非常に重要です。

たとえば、オプション3は(v1 += v2).non_const_method()のようなものでは機能しませんが、Whileでは、次のようになります。

v1+=v2;
v1.non_const_method();
5
luk32

指摘したように、luk32は、この関数によって返されるオブジェクトに変更が許可されないようにするためのものです。これは基本的に、コンパイル時に論理エラーを見つけるのに役立ちます。オブジェクトを変更しないことが確実であり、コードがオブジェクトを変更している場合、それを追跡できます。優れたコーディング慣行と考えることができます。

1
51k