2011-07-26 17 views
13

注:私はg ++コンパイラを使用しています(これはかなり良いと思いますが、標準にかなり近づくはずです)。Intsの配列への参照を宣言するとき、なぜそれがconstポインタへの参照である必要がありますか?


あなたはint型の配列を宣言しているとしましょう:

int a[3] = { 4, 5, 6 }; 

さて、あなたは本当にその配列への参照を宣言したいとしましょうBjarne以外の言語がサポートしていると言う(用事なぜ、 )。

ケース1 - あなたがしようとした場合:

int*& ra = a; 

その後、コンパイラbalksと言う:

"invalid initialization of non-const reference of type `int*&' from a temporary of type `int*'" 

まず第一に、物事、なぜ '' 一時変数(つまりはないです)...

とにかく、非constエラーが表示されたら、私はconstをスローしようとします。

ケース2 - あなたがしようとした場合は:

int*const&rca = a; //wish I knew where the spaces should go (but my other post asking about this sort of protocol got a negative rank while many of the answers got ranked highly -- aha! there are stupid questions!) 

その後すべてが、それはクールにコンパイルされ、そしてあなたは、配列への参照を取得します。これはまた、あなたの元の配列への参照を与える

int* justSomeIntPointer = a; //LINE 1 
int*& rpa = justSomeIntPointer; //LINE 2 

: -

ケース3今ここでは、コンパイルします別のものです。

ここに私の質問です:静的に宣言された配列 の名前はどの時点でconstポインタになりますか? intの配列の名前はintへのポインタでもあることを覚えているようですが、これまでのconstポインタ型から覚えていません...

ケース1のようです宣言された参照(ra)がconstポインタにないため、 'a'が既にconstポインタからintへと始まっていることがあるため、失敗します。

すでに宣言されている参照(rca)がすでにconst-pointer-to-intであるため、ケース2のように見えます。

ケース3もうまく動作しますが、それはなぜですか?想定されるintへのポインター(つまり、配列名 'a')はどの時点でconstポインタになりますか?それをint *(LINE 1)に代入するか、そのint *をint * &(LINE 2)に代入すると起こりますか?

希望はこれが理にかなっています。ありがとう。

答えて

27
int*& ra = a; 

int*はポインタ型ではなく、配列型です。だからこそ、それはaのタイプint[3]にバインドされません。

int* const& ra = a; 

作品、それが

ある
int* const& ra = (int*)a; 

と同等であるためには、一時的なポインタは、概念的には割り当ての右側に作成され、この一時はその後raにバインドされています。

raは、実際には配列の最初の要素へのポインタではなく配列への参照である
int* ra = a; 

:だから最後に、これはよりも良好ではありません。

配列への参照を簡単に宣言:

typedef int array_type[3]; 
array_type& ra = a; 

ない-AS-簡単:

int (&ra)[3] = a; 

C++ 11-簡単:

auto& ra = a; 

静的に宣言された配列の名前はどの時点でconstポインタになりますか?私はintの配列の名前もintへのポインタであることを覚えているようですが、私はそれがconst-pointer-to-intであることを覚えていません...

これは正しい質問をする!配列からポインタへの崩壊が起こったときに理解すれば、あなたは安全です。 「コピー」のいずれかの種類が試みられたとき

  • 減衰は変換の一種であるとすることができます(Cが配列の直接コピーすることはできませんので)

    • 崩壊が起こる:単純に考慮すべき二つのものがあります置きますタイプが一致しないときにいつでも変換が許可されます。

    最初の種類は通常テンプレートで発生します。 。タイプint[3]の配列は、あなたが既にアクションでそれを見てきた2つ目については

    にコピーすることはできませんので、そうtemplate<typename T> pass_by_value(T);与えられ、その後、pass_by_value(a)は、実際に、int*を渡します:これは2番目のケースで起こりますint* const&int[3]にバインドできませんが、一時的にint*にバインドできるため、変換が行われます。

  • -2

    aはmallocまたはnewを使用してスタック上で宣言したため、一時変数ではありません。

    +0

    ので、一時的な変数は、常にCONSTていますか? – Jimmy

    +3

    @Jimmy:一時変数は必ずしもconstではありませんが、言語は非const参照に直接バインドすることを禁じています。配列 'a'は一時的ではありませんが、一時的な配列からポインタへの変換の結果として生じるポインタです。 –

    +0

    スタック上に宣言されているのは、 '自動保存期間があります'という意味です。つまり、そのブロック/オブジェクトが含まれているときに範囲外になります。動的に割り当てられたオブジェクトを手動で管理して、プラスのポイントにすることはほとんどありません。最後に必要なことは、なぜ動的割り当てが優れているかについての別の誤った考えです。これは、非常に明確で異なる意味を持つ用語である_temporary_の誤った定義を呼び出すため、特に悪いことです。 –

    0

    静的に宣言された配列の名前はどの時点でconstポインタになりますか?私はintの配列の名前もintへのポインタであることを覚えているようですが、私はconstポインタのint型であることを覚えていません...

    値はcppファイルの中にあるので、それは定数です。

    あなただけ使用することができます。

    const int *pToArray = a; 
    

    または

    const int *pToArray = (const int*)&a[0]; 
    
    2

    ほとんどの人が作った非常に大きな間違い(面接の質問)は、配列の名前がポインタと同じだと思うということです。そうではありません。このミスは、特にバグをリンクするCプログラムの多くのバグを引き起こし、デバッグが非常に困難です。 diffrenceは次のとおりです。配列の名前は、構造体の最初の要素である配列、配列です。ただし、配列型の型はポインタ型ではなく、配列型です。一方、ポインタは、他の情報のない1つのものへのポインタに過ぎません。ポインタの型はポインタ型です。配列型にはスタック上にあるかどうかを知っているような他のいくつかのプロパティがあります。したがって、 "一時的"です。あなたのケースの一時的なエラーは、一時変数が参照に割り当てられないようにするチェックから来ています。 constキーワードはチェックをオフにします。一方、ポインタ型は "一時的"という概念を持たない。ここで、コンパイラを騙して、スタックにあるものへの参照を割り当てたいとします。その場合は、ポインタにする必要があります。どうやって?

    int * & ra = & a [0];

    上記の場合、最初に値を取得し、&(演算子のアドレス)を使用してpointerTypeを作成します。現在、ポインタ型には、スタック上にあるかどうか(一時変数)に関する情報はありません。しかし、これは、配列の最初の要素へのポインタへの参照を作成します。 (したがって、単にポインタ型、いないのArrayType)

    1

    あなたが本当に配列への参照をしたい場合は、次を使用する必要があります:あなたはint *&を作成しようとしている何

    int a[3] = { 4, 5, 6 }; 
    int (&ra)[3] = a; 
    

    を基準としintへのポインタ。これは同じタイプではありません。そして、参照の値を変更できない値(配列のアドレス)で初期化するときは、ポインタconst(intではない)を宣言する必要があります。

    1

    あなたはintの配列があります。今

    int a[3] = { 4, 5, 6 }; 
    

    を、この行:

    int*& ra = a; 
    

    は、ポインタへの参照を作成します。一時的なポインタ(配列aから変換されたもの)を作成するので、コンパイラは一時参照を参照に割り当てることを禁じているので、不平を言っています。

    int *pa = a; 
    int *& rpa = pa; 
    

    定数の参照が一時への参照を保持することができますが、あなたはすでにそれを見つけた:

    ので、それを修正するには、ポインタを作成し、ポインタへの参照に割り当てる必要があります。

    template< typename T, size_t N > 
    size_t ArraySize(T (&)[ N ]) 
    { 
        return N; 
    } 
    

    この関数は配列への参照を取得し、それはサイズだ返します - あなたが(配列への参照について)尋ねた何

    配列への参照を作成する方法について最も有名な例がこれです。

    8

    C++の "array"という語は、角かっこ([])で綴られています。 C++でsomething-array-somethingを宣言したい場合は、宣言に角括弧を付ける必要があります。代わりにアスタリスク*を書くと、ポインタが得られます。ポインタと配列は2つの異なるものです。

    これは配列へのリファレンスです:

    int (&ra) [3] = a; 
    
    関連する問題