5


0

文字列s; &s + 1;法的? UB?

次のコードを見てください。

#include
#include
#include
#include
#include
using namespace std;

int main()
{
    string myAry[] =
    {
        "Mary",
        "had",
        "a",
        "Little",
        "Lamb"
    };
    const size_t numStrs = sizeof(myStr)/sizeof(myAry[0]);

    vector myVec(&myAry[0], &myAry[numStrs]);

    copy( myVec.begin(), myVec.end(), ostream_iterator(cout, " "));

    return 0;
}

ここで興味深いのは &myAry [numStrs]`です:numStrsは5に等しいため、 `&myAry [numStrs]`は存在しないものを指します。配列内の_sixth_要素。 上記のコードには、別の例があります: `myVec.end()。これは、ベクトル myVec`の最後の1つを指します。 存在しないこの要素のアドレスを取得することは完全に合法です。 `string`のサイズを知っているので、 string`sのCスタイルの配列の6番目の要素のアドレスが指す場所を知っています。 このポインターのみを評価し、間接参照しない限り、問題ありません。 同等かどうかを他のポインターと比較することもできます。 STLは、イテレーターの範囲で動作するアルゴリズムでこれを常に行います。 `end()`イテレータは終わりを過ぎてポイントし、ループはループを続けますが、カウンター `!= end()`です。

だから今これを検討してください:

#include
#include
#include
#include
#include
using namespace std;

int main()
{
    string myStr = "Mary";
    string* myPtr = &myStr;
    vector myVec2(myPtr, &myPtr[1]);

    copy( myVec2.begin(), myVec2.end(), ostream_iterator(cout, " "));

    return 0;
}

このコードは合法で明確に定義されていますか? `&myAry [numStrs]`のように、配列要素のアドレスを最後以降に取得することは正当であり、明確に定義されています。

2 Answer


12


配列の「終わりを超えて」へのポインターを持つことは合法であり、UBではありません。また、任意の単一オブジェクトを長さ1の配列にあるかのように扱うことができます。ただし、 &ptr [1]`の逆参照とアドレス取得の技術的理由により、代わりに `ptr + 1`を使用する必要があります。 これは、 `array + size`になる&array [size] `にも適用されます。

私が知っているすべてのプラットフォームで期待どおりに動作しますが、明確に正しいフォームを使用するのがどれほど簡単かを考えると、代わりにそれをしない理由はありません。


5


5.6 / 4のC ++標準「加算演算子」には次のように書かれています。

_ これらの演算子の目的上、非配列オブジェクトへのポインターは、オブジェクトの型を要素型として持つ長さ1の配列の最初の要素へのポインターと同じように動作します。 _

C99標準6.5.6 / 7は、本質的に同じことを言っています。