1

存在しない可能性のある配列要素への参照を作成して、ループでの入力を節約したいと思います。そうすることは合法ですか?簡単な例:

#include<vector>
#include<iostream>
#include<initializer_list>
using namespace std;
int main(void){
    vector<int> nn={0,1,2,3,4};
    for(size_t i=0; i<10; i++){
        int& n(nn[i]); // this is just to save typing, and is not used if invalid
        if(i<nn.size()) cout<<n<<endl;
    }
};

https://ideone.com/nJGKdWはコードを正常にコンパイルして実行します (g++ と clang++ の両方でローカルで試しました) が、それを当てにできるかどうかはわかりません。

PS:どちらの gcc も clang も文句を言いませ-Wall-g

編集 2:議論は配列のインデックス付けに焦点を当てています。実際のコードは実際に使用std::listされ、フラグメントは次のようになります。

std::list<int> l;
// the list contains something or not, don't know yet
const int& i(*l.begin());
if(!l.empty()) /* use i here */ ;

EDIT 3:私がしていたことに対する法的解決策は、イテレータを使用することです:

std::list<int> l;
const std::list<int>::iterator I(l.begin()); // if empty, I==l.end()
if(!l.empty()) /* use (*I) here */ ;
4

3 に答える 3

3

いいえ、合法ではありません。の宣言でベクトルから範囲外のデータを読み取っているnため、プログラムの動作は未定義です。

于 2013-06-15T08:58:53.433 に答える
0

いいえ、次の 2 つの理由からです。

  1. 標準状態 (8.3.2):

    参照は、有効なオブジェクトまたは関数を参照するように初期化する必要があります

  2. std::vector::operator[]コンテナーのサイズを超えてもN、関数が例外をスローしないことを保証します (非スロー保証、 以外の境界チェックなしat())。ただし、その場合の動作は未定義です。

したがって、プログラムは整形式ではなく (箇条書き 1)、未定義の動作を呼び出します (箇条書き 2)。

于 2013-06-15T10:07:42.907 に答える
0

これが仕様で「許可」されているとしたら、私は驚くでしょう。ただし、割り当ての範囲外にある要素のアドレスを格納することはほとんどの場合、それ自体で問題を引き起こすことはありません。極端な場合、ポインタ型をオーバーフローさせて問題を引き起こす可能性があります。私は考えます。

言い換えると、iが のサイズの WAY 外にある場合nn、問題になる可能性があります。必ずしもi巨大である必要はありません。ベクトルの各要素が数メガバイト (または 64 ビット マシンではギガバイト) の場合、非常に迅速に実行できます。アドレス範囲で問題が発生します。

しかし、仕様を引用するように私に頼まないでください。おそらく他の誰かがそうするでしょう。

編集:コメントによると、少なくともデバッグビルドでは、有効なサイズ外の値のアドレスを要求しているため、これによりvector実装がアサートされるか、そうでなければ「これが間違っていることを警告する」可能性があります。

于 2013-06-15T08:59:28.520 に答える