C/C++

C++の参照

投稿日:2018年6月6日 更新日:

参照変数

  • 参照の宣言 : 「 参照先の型&  参照変数名 = 参照先の変数; 」
  • 参照変数は宣言と同時に代入する必要がある。初期化で必ず参照先の変数を指定する必要がある。参照とは「他の変数を指し示す変数」ですので、その参照先の変数がすでに存在している必要があります。参照先を用意せずに参照だけ宣言すると、コンパイルエラーが発生します。
  • 代入された参照変数は、元の変数の別名として機能します。その意味でも参照はポインタとよく似ている。
  • 参照変数には "NULL" を代入することはできません(ポインタのように宣言するのみが出来ない。宣言と同時に代入する必要がある)。よって、引数の参照渡しにおいて、引数の値がNULLになることはない(ポインタのようにNULLチェック不要)。
  • 参照は参照先を変更できません。一度参照を宣言したら、参照先を変えることは出来ない。そもそも参照先を変更するための書き方が存在しない。
  • 参照は参照先アドレスが記録されているメモリ・アドレスを獲得出来ない。そもそもそのための書き方が存在しない。
  • 参照変数は、参照先の変数とまったく同じになります。一方の値を変えれば、もう一方の値も変わります。
  • 参照変数を変数に代入すると(ディープ)コピーされる。

 

参照渡し

  • 引数の型に&を入れる。
  • 値渡しのように、引数の受け渡しにコピーが発生しない。そのため、引数のコンストラクタやデストラクタは呼び出されない。
  • 関数内での変更が呼出し側に反映される。
  • 関数内で変更しない場合はconst属性を付ける。
  • 参照渡しの変数をローカル変数に代入すると(ディープ)コピーになる。

 

参照の戻り値

  • 呼び元で破棄されたオブジェクトを参照しているダメな例
  • 関数内のローカル変数の参照を返すと、この変数は関数が終了すると削除されるので、返された参照を使ってアクセスすれば、その変数は存在しないので例外が発生する。

  • ポインタで戻すダメな例
  • 問題ないコードだけど使用者にメモリ解放の責任を負わせる

  • 参照の戻り値を変数に代入すると(ディープ)コピーされる。

 

値渡し

  • 関数の呼出しでデータを渡す引数:pstr が作成され、このときにstringのコンストラクタが呼び出されます(正確には「コピーコンストラクタ」。データのコピー専用のコンストラクタ)。
  • 関数が終了する直前に戻り値が新規に作成され、コンストラクタが呼び出されます。関数が戻り値と入れ替わるように、戻り値のために新しく変数が作成される。これを一時オブジェクトといいます。この一時オブジェクトを__tempとすると、str = __temp; という風に関数が置き換えられ、このとき__tempのコピーコンストラクタが呼び出されて、returnの右辺値のpstrがコンストラクタ引数として渡されます。つまりreturnの右辺値がそのまま使われるわけではなく、わざわざ一時オブジェクトを作成する。
  • その後、関数内の変数がすべて削除され、このとき引数pstrのデストラクタも呼び出されます。
  • さらに、一時オブジェクトの寿命はその行のみなので、str = __temp;の次の行に移った瞬間、__tempのデストラクタが呼び出され、削除されます。
  • まとめると、引数のコンストラクタ->一時オブジェクトのコンストラクタ->引数のデストラクタ->一時オブジェクトのデストラクタという順番でコンストラクタとデストラクタが呼ばれてしまうので、時には大きな負担になってしまいます。

 

 

参考にさせて頂いたページ

参照を使おう!

バケツリレーの限界

C++編【言語解説】 第16章 コピー操作と参照

第16回目 参照、それはポインタと同じ?違う?

値渡しか、参照渡しか

C++でstd::stringをどう返すべきか Part1

 

 

スポンサーリンク

スポンサーリンク

-C/C++

執筆者:

関連記事

C言語その他

グローバル変数のstatic属性 グローバル変数にstaticを付けた時のstaticは「静的」という意味ではなく、スコープが「宣言位置からそのコンパイル単位の終わりまで」となる。 第10回目 4大メ ...

Linux C ライブラリについて

実行時のライブラリ探索 実行時のライブラリ探索パスは/etc/ld.so.confに書いてあるディレクトリ。 環境変数LD_LIBRARY_PATHでも指定可能。 Linux共有ライブラリの簡単なまと ...

ポインタ

  ポインタ int* a 変数 a の中身はアドレスを示す。 ポインタ変数 *a はアドレス(aの値)のメモリの値をポインタ変数(*a)として扱う事ができる。 *a=1; はaの値(アドレ ...


プロフィール
管理人です。 業務プログラムに勤しむ人です プロフィール詳細


検索

カテゴリ

アーカイブ