参照初期化
提供: cppreference.com
参照をオブジェクトに束縛します。
目次 |
[編集]構文
T T T T | (1) | ||||||||
T T T T | (2) | (C++11以上) | |||||||
Rfn( T& arg); または Rfn( T&& arg); が与えられたとき、 fn fn | (3) | ||||||||
T& fn() または T&& fn() の中で、
| (4) | ||||||||
Class の定義の中で、 T& ref; または T&& ref; が与えられたとき、 Class | (5) | ||||||||
[編集]説明
T
への参照は、 T
型のオブジェクト、 T
型の関数、または T
に暗黙に変換可能なオブジェクトを用いて初期化できます。 いったん初期化されると、参照は別のオブジェクトを参照するように変更することはできません。
参照は以下の状況で初期化されます。
1) 名前付きの左辺値参照変数が初期化子付きで宣言されたとき。
2) 名前付きの右辺値参照変数が初期化子付きで宣言されたとき。
3) 関数呼び出し式で、その関数の引数が参照型のとき。
4)return 文で、その関数が参照型を返すとき。
参照初期化の効果は以下の通りです。
- 初期化子が波括弧初期化子リスト
{
arg1, arg2, ...}
の場合は、リスト初期化のルールに従います。
- そうでなく、参照が左辺値参照の場合、
- object が左辺値式であり、その型が
T
またはT
からの派生であり、 cv 修飾が等しいかより少ない場合、参照はその左辺値によって表されるオブジェクトまたはその基底クラスの部分オブジェクトに束縛されます。
- object が左辺値式であり、その型が
double d =2.0;double& rd = d;// rd は d を参照します。constdouble& rcd = d;// rcd は d を参照します。struct A {};struct B : A {} b; A& ra = b;// ra は b 内の A 部分オブジェクトを参照します。const A& rca = b;// rca は b 内の A 部分オブジェクトを参照します。
- そうでなく、 object の型が
T
でもT
からの派生でもなく、 object がT
またはT
からの派生いずれかの cv 修飾が等しいまたはより少ない型の左辺値への変換関数を持つ場合、参照はその変換関数によって返された左辺値によって表されるオブジェクト (またはその基底クラスの部分オブジェクト) に束縛されます。
- そうでなく、 object の型が
struct A {};struct B : A { operator int&();};int& ir = B();// ir は B::operator int& の結果を参照します。
- そうでなく、参照が右辺値参照または(C++11以上)const への左辺値参照の場合、
- object がビットフィールドでない右辺値または関数左辺値であり、その型が
T
またはT
からの派生いずれかの cv 修飾が等しいまたはより小さい型の場合、参照は初期化子の式の値またはその基底クラスの部分オブジェクトに束縛されます (必要であれば一時オブジェクトの具体化の後で)(C++17以上)。
- object がビットフィールドでない右辺値または関数左辺値であり、その型が
struct A {};struct B : A {};extern B f();const A& rca2 = f();// B の右辺値の A 部分オブジェクトに束縛されます。 A&& rra = f();// 同上。 int i2 =42;int&& rri =static_cast<int&&>(i2);// i2 に直接束縛されます。
- そうでなく、 object の型が
T
でもT
からの派生でもなく、 object がT
またはT
からの派生いずれかの cv 修飾が等しいまたはより少ない型の右辺値または関数左辺値への変換関数を持つ場合、参照はその変換関数の結果またはその基底クラスの部分オブジェクトに束縛されます (必要であれば一時オブジェクトの具体化の後で)(C++17以上)。
- そうでなく、 object の型が
struct A {};struct B : A {};struct X { operator B();} x;const A& r = x;// 変換の結果の A 部分オブジェクトに束縛されます。 B&& rrb = x;// 変換の結果に直接束縛されます。
- そうでなければ、 object は
T
に暗黙に変換されます。 参照は変換の結果に束縛されます (一時オブジェクトの具体化の後で)(C++17以上)。 object (または、変換がユーザ定義変換によって行われた場合は、その変換関数の結果) がT
またはT
からの派生型の場合、その cv 修飾はT
と等しいかそれより少なくなければなりません。 また、参照が右辺値参照の場合は、左辺値であってはなりません。(C++11以上)
- そうでなければ、 object は
conststd::string& rs ="abc";// rs は文字配列からコピー初期化された一時オブジェクトを参照します。constdouble& rcd2 =2;// rcd2 は値 2.0 を持つ一時オブジェクトを参照します。int i3 =2;double&& rrd3 = i3;// rrd3 は値 2.0 を持つ一時オブジェクトを参照します。
[編集]一時オブジェクトの生存期間
参照が一時オブジェクトまたはその部分オブジェクトに束縛されたとき、その一時オブジェクトの生存期間はその参照の生存期間と一致するように延長されます。 ただし以下の例外があります。
- return 文で関数の戻り値に束縛される一時オブジェクトは延長されません。 その return 式の終わりでただちに破棄されます。 そのような関数は常にダングリング参照を返します。
| (C++14未満) |
- 関数呼び出しで参照引数に束縛される一時オブジェクトは、その関数呼び出しを含む完全式の終わりまで存在します。 その関数がその完全式よりも長生きする参照を返すと、それはダングリング参照になります。
- new 式で使用される初期化子内の参照に束縛される一時オブジェクトは、その初期化されたオブジェクトが存在する限りではなく、その new 式を含む完全式の終わりまで存在します。 その初期化されたオブジェクトがその完全式よりも長生きする場合、その参照メンバはダングリング参照になります。
struct A {int&& r;}; A a1{7};// OK、生存期間は延長されます。 A a2(7);// well-formed ですが、ダングリング参照です。 | (C++20以上) |
一般的に、一時オブジェクトの生存期間は「渡す」ことによってさらに延長することはできません。 一時オブジェクトを束縛するために使用された参照から初期化された第2の参照は、生存期間に影響を与えません。
[編集]ノート
初期化子を持たない参照は、関数の引数の宣言、関数の戻り値型の宣言、クラスメンバの宣言、および extern
指定子付きの場合にのみ、現れます。
[編集]例
Run this code
#include <utility>#include <sstream> struct S {int mi;conststd::pair<int, int>& mp;// 参照メンバ}; void foo(int){} struct A {}; struct B : A {int n; operator int&(){return n;}}; B bar(){return B();} //int& bad_r; // エラー、初期化子がありません。externint& ext_r;// OK。 int main(){// 左辺値の例int n =1;int& r1 = n;// オブジェクト n への左辺値参照。constint& cr(n);// 参照は cv 修飾を増やすことができます。volatileint& cv{n};// 任意の初期化子構文が使用できます。int& r2 = r1;// オブジェクト n への別の左辺値参照。// int& bad = cr; // エラー、 cv 修飾を減らすことはできません。int& r3 =const_cast<int&>(cr);// const_cast が必要です。 void(&rf)(int)= foo;// 関数への左辺値参照。int ar[3];int(&ra)[3]= ar;// 配列への左辺値参照。 B b; A& base_ref = b;// 基底部分オブジェクトへの参照。int& converted_ref = b;// 変換の結果への参照。 // 右辺値の例// int& bad = 1; // エラー、左辺値参照は右辺値に束縛できません。constint& cref =1;// 右辺値に束縛されます。int&& rref =1;// 右辺値に束縛されます。 const A& cref2 = bar();// B の一時オブジェクトの A 部分オブジェクトへの参照。 A&& rref2 = bar();// 同上。 int&& xref =static_cast<int&&>(n);// n に直接束縛します。// int&& copy_ref = n; // エラー、左辺値に束縛できません。double&& copy_ref = n;// 値 1.0 の右辺値の一時オブジェクトに束縛。 // 一時オブジェクトの生存期間についての制限std::ostream& buf_ref =std::ostringstream()<<'a';// ostringstream の一時オブジェクトは// operator<< の左の被演算子に束縛されますが、// その生存期間はセミコロンで終わるため、// buf_ref はダングリング参照になります。 S a {1, {2, 3}};// 一時オブジェクト pair {2, 3} は参照メンバ a.mp に// 束縛され、その生存期間は a と一致するように延長されます。 S* p = new S{1, {2, 3}};// 一時オブジェクト pair {2, 3} は参照メンバ p->mp に// 束縛されますが、その生存期間はセミコロンで終わります。// p->mp はダングリング参照になります。 delete p;}