エラー:タイプ 'int'の右辺値からのタイプ 'int&'の非const参照の無効な初期化


87

間違った形式:

int &z = 12;

正しい形式:

int y;
int &r = y;

質問
最初のコードが間違っているのはなぜですか?タイトルの誤りの「意味」とは?


4
一時的なものを非定数参照にバインドすることはできません。この場合、int(12)は一時的なものです。
Prasoon Saurav 2011年

@PrasoonSaurav一時的な12とはどういう意味ですか?ここに概念がない(私の側では:))
Aquarius_Girl

2
この制限には厳密な技術的理由はないことに注意してください。一時的なものへの変更可能な参照を許可するのと同じくらい簡単に実装できたでしょう。このような構造は設計が不十分であり、本物のユーティリティよりも不注意に悪用されるリスクがはるかに高いため、これを禁止することはC ++の設計上の決定です。(私は一度だけそのようなものの
不自然

@KerrekSB右辺値オブジェクトへのバインディング参照の最も一般的な必要性は、おそらく(ostringstream() << "x=" << x).str()
curiousguy 2011年

@curiousguy:はい、それは私が投稿したリンクの内容です。
Kerrek SB 2011

回答:


132

C ++ 03 3.10 / 1によると、「すべての式は左辺値または右辺値のいずれかです。」左辺値と右辺値は、オブジェクトではなく式のプロパティであることを覚えておくことが重要です。

左辺値は、単一の式を超えて存続するオブジェクトに名前を付けます。たとえば、obj*ptrptr[index]、および++xすべて左辺値です。

右辺値は、それらが存在する完全な式の終わり(「セミコロン」)で蒸発する一時的なものです。たとえば、1729x + ystd::string("meow")、およびx++すべての右辺値です。

address-of演算子では、その「オペランドは左辺値でなければならない」必要があります。1つの式のアドレスを取得できる場合、その式は左辺値です。それ以外の場合は、右辺値です。

 &obj; //  valid
 &12;  //invalid

2
1つの式のアドレスを取得できる場合、その式は左辺値です。それ以外の場合は右辺値です。」C ++だけがそれほど単純だった場合!(ただし、ここではニュアンスはあまり関係ありません)「値は一時的なものです」一時的なものは何ですか?オブジェクト?
curiousguy 2011年

2
@curiousguyRvaluesは、それらが存在する完全な式の終わりに消える一時的なものです。エクスプレスint & = 12;が無効である理由を簡単に答えるために、標準では、文字列リテラルは左辺値であり、他のリテラルは右辺値であるとされています。
BruceAdi

@curiousguy:はい。右辺値は一時オブジェクトですが、すべての右辺値が一時オブジェクトであるとは限りません。いくつかはオブジェクトでさえありません。
ナワズ

"たとえば、1729、x + y、std :: string(" meow ")、およびx ++はすべて右辺値です "しかしstd::string("meow")、型のオブジェクトを作成し、std::stringこのオブジェクトを指定する右辺1729値を生成します。副作用はなく、値を生成します。タイプの右辺値としての1729 int
curiousguy 2011年

1
@curiousguy:このステートメント"Lvalues name objects that persist beyond a single expression."は100%正しいステートメントです。それどころか、(const int &)1これは「名前付き」オブジェクトではないため、例は正しくありません。
nawaz 2011年

53
int &z = 12;

右側でintは、型の一時オブジェクトが整数リテラルから作成されますが、一時オブジェクト12を非const参照にバインドすることはできません。したがって、エラー。それは同じです:

int &z = int(12); //still same error

なぜ一時が作成されるのですか?参照はメモリ内のオブジェクトを参照する必要があり、オブジェクトが存在するためには、最初に作成する必要があります。オブジェクトには名前がないため、一時オブジェクトです。名前はありません。この説明から、2番目のケースが問題ない理由がかなり明らかになりました。

一時オブジェクトはconst参照にバインドできます。つまり、次のことができます。

const int &z = 12; //ok

C ++ 11および右辺値リファレンス:

完全を期すために、C ++ 11では一時オブジェクトにバインドできる右辺値参照が導入されていることを付け加えておきます。したがって、C ++ 11では、次のように記述できます。

int && z = 12; //C+11 only 

&&代わりがあることに注意してください&。また、それconstはもう必要ないことに注意してください。zバインドするオブジェクトは、integral-literalから作成された一時オブジェクトですが、は12

C ++ 11では右辺値参照が導入されたため、int&以降、左辺値参照と呼ばれるようになりました


10

12は、で参照されるデータとは異なり、変更できないコンパイル時定数int&です。あなたにできることは

const int& z = 12;

2
@curiousguy、一貫して、「これらはC ++ルールであることを理解する必要があります。これらは存在し、正当化する必要はありません」(初版は言うまでもありません)。自分に合ったものを与えないというあなたの不満は必要ないとどう解釈しますか?
MichaelKrelin-ハッカー2011年

2
@ MichaelKrelin-ハッカー:技術的にはそうではなく、参照を値(またはコンパイル時定数)にバインドすることはできません。標準は実際に何が起こるかについて非常に明確です。そうでない場合、タイプ「cv1T1」の一時的なものが作成されて非参照コピー初期化(8.5)のルールを使用して、イニシャライザ式から初期化されます。次に、参照は一時にバインドされます。つまり、構文は許可されますが、セマンティクスは、参照を定数にバインドするセマンティクスではなく、暗黙的に作成された一時にバインドします。
デビッドロドリゲス-ドリビア2011年

1
@curiousguy:言語のルールは設計の一部であり、多くの場合、言語がそのように設計された理由については正当化されます。この特定のケースでは、Cの場合と同様に、値のアドレスを取得することはできません(値のアドレスはありません)。また、参照をバインドすることもできません。ここで、void f( vector<int> const & )変更されないベクトルを渡すのが慣用的な関数について考えてみましょう。ここでの問題は、それf( vector<int>(5) )が正しくないことであり、ユーザーvoid f( vector<int> v ) { f(v); }は些細な別のオーバーロードを提供する必要があります。
デビッドロドリゲス-ドリビア2011年

1
...これは言語のユーザーにとって苦痛であるため、設計者はコンパイラーが同等の操作を実行することを決定しました。呼び出しf( vector<int>(5) )で、コンパイラーは一時的なものを作成し、その一時的なものに参照をバインドします。同様に5直接からの暗黙の変換があった場合。これにより、コンパイラーは関数の単一の署名を生成でき、関数の単一ユーザー実装が可能になります。それ以降、一貫性を保つための定数参照の残りの使用についても、同様の動作が定義されます。
デビッドロドリゲス-ドリビア2011年

1
@ MichaelKrelin-ハッカー:参照はオブジェクトのエイリアスであり、値はオブジェクトではありません。コンテキストに応じて、参照はエイリアスにすることができます。コンパイラは参照を削除し、識別子を使用して元のオブジェクトが意味するものを意味します(T const & r = *ptr;r関数でのその後の使用は、に置き換えることができ、実行時に存在する必要*ptrはありrません)または、エイリアスするオブジェクトのアドレスを保持することによって実装する必要がある場合があります(参照をオブジェクトのメンバーとして格納することを検討してください)。これは、自動逆参照ポインターとして実装されます。
デビッドロドリゲス-ドリビア2011年

4

非constおよびconst参照バインディングは異なるルールに従います

これらはC ++言語のルールです:

  • リテラル数(12)で構成される式は「右辺値」です
  • 右辺値を使用して非定数参照を作成することは許可されていません:int &ri = 12;形式が正しくありません
  • 右辺値を使用してconst参照を作成することは許可されています。この場合、名前のないオブジェクトがコンパイラーによって作成されます。このオブジェクトは、参照自体が存在する限り存続します。

これらはC ++ルールであることを理解する必要があります。彼らはただです。

わずかに異なるルールで、異なる言語、たとえばC ++ 'を発明するのは簡単です。C ++ 'では、右辺値を使用して非定数参照を作成することが許可されます。ここには矛盾したり不可能なことは何もありません。

しかし、プログラマーが意図したものを取得できない可能性があるリスクの高いコードが許可されるため、C ++設計者はそのリスクを回避することを正しく決定しました。


0

参照は、変更される可能性のあるもの(左辺値)への「隠しポインター」(null以外)です。それらを定数に定義することはできません。それは「可変」のものでなければなりません。

編集::

私は考えています

int &x = y;

ほぼ同等

int* __px = &y;
#define x (*__px)

ここ__pxで、は新しい名前であり、参照#define xの宣言を含むブロック内でのみ機能しxます。


1
参照がconst:)
MichaelKrelin-ハッカー2011年

しかし、ポスターの例はそうではありませんでしたconst
Basile Starynkevitch 2011年

はい、私はあなたの言い回し「参照は変更される可能性のあるものへのポインタです」を意味しました-それは非コストの参照についてです。
MichaelKrelin-ハッカー2011年

参照は、変更できるものへの「隠されたポインタ」「間違った」「間違った」変更できるもの(左辺値)です。」間違った
curiousguy 2011年

@ロキ:もっと説明してもらえますか?
Basile Starynkevitch 2011年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.