C++11の右参照

3901 ワード

目次
  • 一、問題導入
  • 二、右および右参照
  • 2.1左値(lvalue)と右値(rvalue)
  • 2.2左参照と右参照
  • まとめ
  • 参考資料
  • C++11はstd::moveの意味、右値の参照、移動構造、および完全な転送などの特性を導入した.この部分は比較的長いので,3編に分けて述べる.
    これらの特性を理解する前に、いくつかの問題を導入します.
    一、問題の導入
  • 関数の戻り値が伝値のときに何回オブジェクト構造、何回コピーが発生しますか?
  • 関数のパラメータは値伝達時に何回オブジェクト構造が発生しますか?

  • まずコードを見てみましょう
    // main.cpp
    #include 
    using namespace  std;
    
    class A{
    public:
       A(){
          cout<

    g++を使用してコンパイルします.注意-fno-elide-constructorsを使用して構造最適化を省略
    g++ main.cpp -fno-elide-constructors

    以下の出力が得られます
    class A construct!
    class A destruct!
    class A copy!
    class A destruct!
    class A destruct!
    A a=get_A_value();行のコードが1回のオブジェクト構造と2回のオブジェクトのコピー構造を生成することがわかります!具体的には
  • get_A_value()ではA()が一時オブジェクトを構築し,一度構造が発生した.

  • 関数が戻ると一時オブジェクトがコピーされて戻り値となり、1回のコピーが発生します.

  • A=関数戻り値がコピー構造となる.


  • コンパイラ最適化(デフォルト)を使用すると、一時的なオブジェクトのコピーと、戻り値で最終的なオブジェクトのコピーを構築するものは省略されます.すなわち,コピーとプロファイルは1回のみである.
    class A construct!
    class A destruct!

    上のコードを変更したら
    // ... A
    
    void pass_A_by_value(A a){
    
    }
    int main(){
        A a;
        pass_A_by_value(a);
        return 0;
    }

    最適化g++ main.cpp -fno-elide-constructorsを削除すると出力は
    class A construct!
    class A copy!
    class A destruct!
    class A destruct!

    1回の構造に1回のコピーを加えます.
    したがって、次の面接でこの質問をすると、デフォルトではコンパイラによって最適化された一時オブジェクトのコピーが省かれ、-fno-elide-constructorsを使用して最適化を省略すると、一時オブジェクトのコピーも考慮されると言えます.
    実際には、最適化されていない場合、コピーコンストラクション関数が呼び出されます.
  • 関数内のローカルオブジェクトが戻り値として戻る(参照ではない)ときにコピー(一時オブジェクトにコピーして戻る)
  • が発生する.
  • 関数パラメータが伝値の場合、コピー構造
  • が発生する.
  • あるオブジェクトが別のオブジェクトで初期化するとき
  • .
    オブジェクトの頻繁な構造はプログラムのオーバーヘッドであり、特にオブジェクト内部にメモリ(例えばnewから出てきたメンバー)が山積みされている場合、構造をコピーするたびにnewでメモリを申請する必要があり、性能の低下をもたらす.場合2については、関数パラメータが読み取り専用である場合(すなわち、プログラム内で修正されない場合)、パラメータとして参照されるpass_A_by_refrence(const A &a)が好ましい.状況1では、コンパイラが最適化します.ケース3では、C++11は**の右参照*を取得し、右の「リソース」moveを新しいオブジェクトに取得するモバイル構造関数の概念を導入し、この過程で新しいメモリを申請することなく、効率とパフォーマンスを向上させることができます.
    したがって,キーワード「移動構造」「移動意味」を理解するには,まず右値と右値の参照を理解する.
    二、右および右参照
    2.1左(lvalue)と右(rvalue)
    一、問題のインポートでは、関数が値を返すときに「一時」しか存在しないオブジェクト(その行を超えると生存期間が終了する)について言及しました.この一時的な戻り値は右の値です.右の値の最も直感的な定義は、その名の通りです.
    代入演算子=右の値で、右の値です.左は左
    のように
    A a = foo(); // foo()    
    char *x = "thu"; // “thu”        
    a = b + c; // b + c          

    C++には、次のような定義があります.
    左の値は住所、名前を取得できます.住所は取得できませんが、名前のないものは右の値です.
    したがって、A a = foo()&aでaのアドレスを取得することができ、aは左の値であるがfoo()のアドレスを取得することができず、(&foo()はコンパイルできず、foo()が返す一時オブジェクトにも名前がないため、右の値である.
    C++11では、右の値には2種類が含まれている.1つは、アポトーシス値(xvalue,eXpiring Value)であり、1つは純右の値(prvalue,Pure Rvalue)[1].関数非参照で返される一時オブジェクト、演算式の結果、1,3.14,'c'のような字面値などはすべて純右値に属する.xvalueは,戻り値A&&の関数戻り値やstd::move()の戻り値など,C++11によって導入される.
    深く考えなければ、左と右の違いを知るだけでいいのです.右の値の詳細な分類については、深く検討する必要はありません.
    2.2左参照と右参照
  • 左値参照は一般的な参照であり、一般的には1つの&で表され、例えば
  • const A &a_ref = a; //      a    

    左の参照は別名に相当し、特定のオブジェクトを指します.
  • 右の値は右の値を引用してその名の通り、右の値の引用で、&&で表します;
  • A &&r_ref = getRvalue(); // r_ref        

    右値参照は別名にも相当し、左値との違いは右値参照が無名変数の別名である.
    getrvalue()は右の値を返す関数で、右の値はこの文の実行が終わると彼の生存期間が終わり、オブジェクトであれば構造関数を呼び出すべきです.しかし==右の値はそれを引用して強引に続命させます==;右の値の参照を使用して右の値を指すと、右の値の生存期間は右の値の参照と同じように長くなり、オブジェクトのプロファイルと構造が少なくなります.
    C++の右値参照には主に2つの用途があり,1つは移動の意味であり,1つは完璧な転送である.これは次の2編でお話しします.
    まとめ
    右の値と移動の意味をインポートするために、まず以下の一時オブジェクトが関数の戻り値と伝達パラメータのときに何回構築されたかを復習した.次に、左値と右値、および右値参照の形式と意味を比較して説明します.移動の意味と完璧な転送の紹介を敷き詰める.
    参考資料
  • Michale Wang|IBM XLコンパイラ中国『C++11を深く理解する』、機械工業出版社
  • 転載先:https://www.cnblogs.com/sunchaothu/p/11343517.html