名前空間
変種
操作

参照初期化

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (非推奨)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

参照をオブジェクトに束縛します。

目次

[編集] 構文

T & ref = object ;

T & ref = { arg1, arg2, ... };

T & ref ( object ) ;

T & ref { arg1, arg2, ... } ;

(1)
T && ref = object ;

T && ref = { arg1, arg2, ... };

T && ref ( object ) ;

T && ref { arg1, arg2, ... } ;

(2) (C++11およびそれ以降)
given R fn ( T & arg ); or R fn ( T && arg );

fn ( object )

fn ( { arg1, arg2, ... } )

(3)
given T & fn () { or T && fn () {

return object ;

(4)
Class::Class(...) : refmember( expr) {...} (5)

[編集] 説明

T への参照は、 T 型のオブジェクト、 T 型の関数、または T に暗黙に変換可能なオブジェクトを用いて初期化できます。 いったん初期化されると、参照は別のオブジェクトを参照するように変更することはできません。

参照は以下の状況で初期化されます。

1) 名前付きの左辺値参照変数が初期化子付きで宣言されたとき。
2) 名前付きの右辺値参照変数が初期化子付きで宣言されたとき。
3) 関数呼び出し式で、その関数の引数が参照型のとき。
4) return 文で、その関数が参照型を返すとき。
5) 参照型の非静的データメンバメンバ初期化子を用いて初期化されるとき。

参照初期化の効果は以下の通りです。

  • 初期化子が波括弧初期化子リスト { arg1, arg2, ... } の場合は、リスト初期化のルールに従います。
  • そうでなく、参照が左辺値参照の場合、
  • object が左辺値式であり、その型が T または T からの派生であり、 cv 修飾が等しいかより少ない場合、参照はその左辺値によって表されるオブジェクトまたはその基底クラスの部分オブジェクトに束縛されます。
double d = 2.0;
double& rd = d;        // rd は d を参照します。
const double& 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 からの派生でもなく、 objectT または T からの派生いずれかの cv 修飾が等しいまたはより少ない型の左辺値への変換関数を持つ場合、参照はその変換関数によって返された左辺値によって表されるオブジェクト (またはその基底クラスの部分オブジェクト) に束縛されます。
struct A {};
struct B : A { operator int&(); };
int& ir = B(); // ir は B::operator int& の結果を参照します。
  • そうでなく、参照が右辺値参照または (C++11およびそれ以降) const への左辺値参照の場合、
  • object がビットフィールドでない右辺値または関数左辺値であり、その型が T または T からの派生いずれかの cv 修飾が等しいまたはより小さい型の場合、参照は初期化子の式の値またはその基底クラスの部分オブジェクトに束縛されます (必要であれば一時オブジェクトの具体化の後で) (C++17およびそれ以降)
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 からの派生でもなく、 objectT または T からの派生いずれかの cv 修飾が等しいまたはより少ない型の右辺値または関数左辺値への変換関数を持つ場合、参照はその変換関数の結果またはその基底クラスの部分オブジェクトに束縛されます (必要であれば一時オブジェクトの具体化の後で) (C++17およびそれ以降)
struct A {};
struct B : A {};
struct X { operator B(); } x;
const A& r = x; // 変換の結果の A 部分オブジェクトに束縛されます。
B&& rrb = x;    // 変換の結果に直接束縛されます。
  • そうでなければ、 objectT に暗黙に変換されます。 参照は変換の結果に束縛されます (一時オブジェクトの具体化の後で) (C++17およびそれ以降)object (または、変換がユーザ定義変換によって行われた場合は、その変換関数の結果) が T または T からの派生型の場合、その cv 修飾は T と等しいかそれより少なくなければなりません。 また、参照が右辺値参照の場合は、左辺値であってはなりません。 (C++11およびそれ以降)
const std::string& rs = "abc"; // rs は文字配列からコピー初期化された一時オブジェクトを参照します。
const double& rcd2 = 2;        // rcd2 は値 2.0 を持つ一時オブジェクトを参照します。
int i3 = 2;
double&& rrd3 = i3;            // rrd3 は値 2.0 を持つ一時オブジェクトを参照します。

[編集] 一時オブジェクトの生存期間

参照が一時オブジェクトまたはその部分オブジェクトに束縛されたとき、その一時オブジェクトの生存期間はその参照の生存期間と一致するように延長されます。 ただし以下の例外があります。

  • return 文で関数の戻り値に束縛される一時オブジェクトは延長されません。 その return 式の終わりでただちに破棄されます。 そのような関数は常にダングリング参照を返します。
  • コンストラクタの初期化子リスト内の参照メンバに束縛される一時オブジェクトは、そのオブジェクトが存在する限りではなく、そのコンストラクタが終了するまでの間のみ持続します (ノート: そのような初期化は DR 1696 以降 ill-formed です)。
(C++14以前)
  • 関数呼び出しで参照引数に束縛される一時オブジェクトは、その関数呼び出しを含む完全式の終わりまで存在します。 その関数がその完全式よりも長生きする参照を返すと、それはダングリング参照になります。
  • new 式で使用される初期化子内の参照に束縛される一時オブジェクトは、その初期化されたオブジェクトが存在する限りではなく、その new 式を含む完全式の終わりまで存在します。 その初期化されたオブジェクトがその完全式よりも長生きする場合、その参照メンバはダングリング参照になります。

一般的に、一時オブジェクトの生存期間は「渡す」ことによってさらに延長することはできません。 一時オブジェクトを束縛するために使用された参照から初期化された第2の参照は、生存期間に影響を与えません。

[編集] ノート

初期化子を持たない参照は、関数の引数の宣言、関数の戻り値型の宣言、クラスメンバの宣言、および extern 指定子付きの場合にのみ、現れます。

[編集]

#include <utility>
#include <sstream>
 
struct S {
    int mi;
    const std::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;      // エラー、初期化子がありません。
extern int& ext_r; // OK。
 
int main() {
// 左辺値の例
    int n = 1;
    int& r1 = n;                    // オブジェクト n への左辺値参照。
    const int& cr(n);               // 参照は cv 修飾を増やすことができます。
    volatile int& 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;        // エラー、左辺値参照は右辺値に束縛できません。
    const int& 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;
}


[編集] 関連項目