1

次のコードを検討してください

void foo( bool forwad )
{
    vector<MyObject>::iterator it, end_it;
    int dir;

    it = some_global_vector.begin() + some_position;
    if( forward )
    {
        dir = 1;
        it += 1;
        end_it = some_global_vector.end();

    }
    else
    {
        dir = -1;
        it -= 1;
        end_it = some_global_vector.begin()-1;
    }

    while( it != end_it )
    {
       if( do_domething() )
         break;

       it += dir;
    }
}

ご覧のとおりforward == false、からの減算がありbegin()、イテレータitがを指すと減算できるため、疑問が生じますbegin()。この悪いポインティングイテレータを逆参照しない限り、問題がなければどこにも見つかりません)。

編集

ISO C ++標準を読み、いくつかの結論があります。vector::begin()住所で内部的に記憶を指し示すことができないという約束はなく0、それで終わりだと思っていましたが、すべてのコンテナは標準のアロケータに依存しています。このアロケーターはnewオペレーターによって異なります。また、new二度と戻らない情報はありません0。ただし、標準のアロケータは演算子にも依存しdelete、この演算子は、を渡しても何もしないと想定されています0。したがって、この事実により、そのポインタを削除する方法がないため、new返すことはできません。0それによって、空でない場合は、そのポイントをvector返すことができません。begin()0

結論:

上記が正しい場合vector::begin()、の内部メモリvectorは連続的であるため、ポイントするインタレータは安全である必要があります。

私は正しいですか?

究極の答え

現在動作しており、将来動作する場合でも、標準による未定義の動作です。これを行う場合は、自己責任で行ってください。詳細については、この同様の質問を参照してください。

4

1 に答える 1

6

beginに渡されたイテレータをデクリメントしたり、を計算したりすることはできませんbegin() - 1

実装では、最後の要素を通過した位置を指定する必要がありますが、開始する前にアドレス空間を使用可能にする必要はありません。したがってbegin() - 1、有効なアドレスではない可能性があります(そして、間違いなく有効なイテレータではありません)。


質問番号2について:

ポインタがnullかどうかif (p == 0)をテストしますが、それはnullポインタすべてのビット0で表す必要があるという意味ではありません。また、すべてビット1、または他の何かである可能性があります。コンパイラの魔法はとにかくテストを機能させます。

無効なアドレスのもう1つの例は、メモリの大きなブロックの割り当てを解除すると、ヒープマネージャーが対応する仮想アドレス空間をプロセスから削除する可能性があることです。

割り当て解除されたスペースの直後から始まる別のメモリブロックは、たとえば、0x10000アドレス0x10000 - 1が存在しなくなった場所にアドレスを持つ可能性があります。ポインタに専用のアドレスレジスタを使用する一部のハードウェアは、無効なポインタをロードするときにトラップすることが知られています。RAMにマップされていないことを検出し、プログラムを中止する可能性があります。0x10000 - 1このようなハードウェアが存在するため、この標準はこれを許可するように作成されています。

これが一般的なデスクトップオペレーティングシステムで通常発生することではなく、言語標準に従って発生する可能性があることです。

于 2011-12-16T12:11:02.630 に答える