左の値、右の値、左の値、右の値、およびその用途

4793 ワード

目次
1.左と右
2.参照
(1)左参照
(2)右参照
3.左引用の用途
(1)複雑な名前変数としての別名
(2)rangeForサイクル用
(3)大きなオブジェクトのコピーを避ける
(4)関与関数におけるパラメータ伝達
4.右参照の用途
(1)コピーを回避し、性能を向上させ、move()を実現する
(2)重荷重パラメータの複雑さを回避しforward()を実現
5.std::moveとstd::swap
CとC++では参照タイプ(reference type)が定義されており、左値参照(lvalue reference)が存在する.
C++11では,右値参照(rvalue reference)という概念が追加された.
1.左と右
左(lvalue):
一時的でないオブジェクトの式.名前があります.住所を取ってもいいです.たとえば、変数を含む非匿名オブジェクト、関数が返す参照、constオブジェクトなどは左です.
右(rvalue):
一時的なオブジェクトの式は、名前がなく、一時的に生成され、アドレスが取得できません.たとえば、即時数、関数の戻り値.
vector arr(3);
const int x = 2;
int y;
int z = x + y;
string str = "foo";

上記のコードでは、arr、str、y、zなどはいずれも左値であり、xも左値であり、彼は修正可能な左値ではない.一方,x+yのような一時(専属変数名なし)の値は右である.
左右の値の変換:
右の値を左の値に変換:変数を直接新規作成して値を割り当てるだけです.int b=a+1;a+1という右の値を左の値に変える
左値を右値に変換:std::move()move(a);aという左の値を右の値に変える
 
2.参照
(1)左参照
左値参照は本質的にポインタ定数であり、左値参照は左値のみを参照できます.
int a = 10;
int &b = a;  //           
b = 20;      //               

int &b=a;        int* const b=&a;

(2)常引用
int &var = 10;

上記のコードはコンパイルできません.10はアドレスを取る操作ができないため、1つの即時数に対してアドレスを取ることができません.即時数はメモリに記憶されていないので、レジスタに記憶されています.常引用で解決できます.
const int &var = 10;

定数10を参照するには、メモリに一時変数が生成されて10が保存されているため、この一時変数はアドレス取得操作を行うことができるので、varが参照するのは実はこの一時変数であり、以下の操作に相当します.
const int temp = 10; 
const int &var = temp;

(3)右参照
左値参照は左値のみを参照し、通常参照は参照によってのみデータを読み取ることができ、constによって定数参照に修飾されているため、データを変更することはできません.したがって、右値参照を増やして、右値を参照するために使用します.
宣言:2つの&&で宣言します.例えば、int&&x=5;
右の値参照は右の値にバインドされ、バインド後に破棄されるはずの右の値の生存期間は、バインドされた右の値参照の生存期間に延長されます.
アセンブリレベルで右値参照で行うことは、定数を格納するために一時的な量を生成することと同じです.しかし、唯一の違いは、右の値の参照は読み書き操作を行うことができ、通常の参照は読み書き操作しかできないことです.
右値参照の存在は、左値参照の代わりになるためではなく、右値(特に一時オブジェクト)の構造を十分に利用して、効率を向上させるためにオブジェクト構造とプロファイル操作を低減するためである.
 
3.左引用の用途
(1)複雑な名前変数としての別名
auto & whichList = theList[myHash(x, theList.size())];

本来複雑な名前の代わりに短いwhichListを使用することで、コードの書き込みを簡略化することができます.
(2)自己呼び出し用
rangeForループにより1つのvectorオブジェクトのすべての値を1増加させることを想定し,次のrangeForループはできない.
for (auto x : arr)   // x           
    ++x;

しかし、参照を使用することでこの目的を達成することができます.
for (auto & x : arr)
    ++x;

(3)関数の戻り参照
findMax関数があると仮定し、vectorの最大要素を返します.与えられたvectorが大きなオブジェクトを格納している場合、次のコードのxコピーはxのメモリに最大値を返します.
auto x = finaMax(vector);

大規模なプロジェクトでは、プログラムのオーバーヘッドが増加することは明らかです.この場合、参照によってこのようなオーバーヘッドを削減できます.
auto & x = findMax(vector);

同様に、関数の戻り値を処理するときに、リファレンスを使用して返すこともできます.ただし、クラス内のプライベート属性が返されると、返される参照が外部から変更されることに注意してください.
関数が値を返すと、一時変数が関数の戻り値のコピーとして生成され、参照を返すと値のコピーは生成されません.
T f(); 一般的なクラスタイプを返します.返されるクラスタイプは左の値にはなりませんが、メンバー関数を直接呼び出して変更したり、クラスタイプを返してレプリケーション構造関数を呼び出したりすることができます.const T f(); このタイプは、const制限子があるため、返されるクラスタイプがメンバー関数を呼び出して変更できないのと同じです.T& f(); 返されるクラスの参照は左の値として使用できます.返されるクラスタイプの参照は、メンバー関数を直接呼び出して変更し、返されるクラスタイプは移動構造関数を呼び出します.const T& f(); 左の値にはできません.メンバー関数の変更を呼び出すことはできません.レプリケーション構造関数は呼び出されません.
(4)関与関数におけるパラメータ伝達
CとC++の関数では,直接入力されたパラメータを関数が修正しても実パラメータの値は変化しない.古典的なSwap()関数のような実パラメータを修正することを望む場合がある.実数の修正を実現するには、入力ポインタと入力参照で実現できます.
直接入力パラメータと入力ポインタについて知らないのは、C++がswap機能を実現するよくあるいくつかのエラー【値伝達、アドレス伝達】を見ることができます.
 
4.右参照の用途
(1)コピーを回避し、性能を向上させ、move()を実現する
右の値のデータを安全に移動することができるという特性は、右の値が移動の意味を表すために使用されるようにする.同じタイプの右の値でオブジェクトを構築する場合は、参照形式でパラメータを入力する必要があります.右値参照は、名前の通り右値を参照するために特別に使用され、左値参照と右値参照はそれぞれリロードされ、左値と右値がコピーと移動の2つの意味実装にそれぞれ呼び出されることを保証します.左の値について、リソースの所有権を明確に放棄した場合、std::move()を使用して右の値参照に変換できます.std::move()実はstatic_cast()の簡単なパッケージ.
(2)重荷重パラメータの複雑さを回避しforward()を実現
C++11の右の値の引用--細かく最も重要な変更!
 
5.std::moveとstd::swap
前述したように、リファレンスを使用してレプリケーションによるメモリのオーバーヘッドを削減できます.
このような状況を考慮すると、要素交換を行う際に、通常、キャッシュ変数tempを使用してデータを保存する.tempに対して直接=の付与操作を行う場合、実際にtempは既存のオブジェクトのメモリをコピーしたが、コピーではなくオブジェクト間の移動だけが必要であり、C++STLのstd::move関数ではこの操作を達成することができる.これは抽象的かもしれませんが、例を見てみましょう.
void swap(vector & x, vector & y)
{
    vector temp = std::move(x);
    x = std::move(y);
    y = std::move(temp);
}

上記の例はC++STLにおけるstd::swapのソースコードの1つであり、std::moveがどのように使用されているかをよく示していると信じられ、ソースコードで使用されても、その効率を説明するのに十分である.
C++は移動構造関数を導入し,このようにaでbを初期化するとaを析出する場合を専門に処理する.
モバイルコンストラクション関数のパラメータは、コピーコンストラクション関数とは異なり、コピーコンストラクション関数のパラメータは左の参照ですが、モバイルコンストラクション関数の初期値は右の参照です.これは、移動コンストラクション関数パラメータが右値または消滅値の参照であることを意味します.すなわち、移動コンストラクション関数は、1つの右値または別のオブジェクトを初期化するときに呼び出されます.move文は、左の値を死の値に変えることです.
モバイルコンストラクション関数が最も多く適用される場所はSTLである.