5

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

#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

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

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

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

    return 0;
}

ここで興味深いのは&myAry[numStrs]、numStrs が 5 に等しいため、&myAry[numStrs]存在しないものを指しているということです。配列の6 番目の要素。上記のコードには、この別の例があります: myVec.end()は、 vector の 1 つ後ろの端を指しmyVecます。存在しないこの要素のアドレスを取得することは完全に合法です。のサイズがstringわかるので、s の C スタイル配列の 6 番目の要素のアドレスがどこをstring指す必要があるかがわかります。このポインターを評価するだけで、逆参照しない限り、問題ありません。等しいかどうかを他のポインターと比較することもできます。STL は、一連の反復子に作用するアルゴリズムで常にこれを行います。イテレータはend()最後を超えてポイントし、ループは counter の間ループし続けます!= end()

だから今これを考えてみましょう:

#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

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

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

    return 0;
}

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

4

2 に答える 2

12

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

あなたが持っているものは、私が知っているすべてのプラットフォームで期待どおりに機能しますが、明確に正しい形式を使用するのがいかに簡単かを考えると、代わりにそれを行わない理由はないと思います.

于 2010-03-08T23:27:26.927 に答える
5

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

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

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

于 2010-03-08T23:31:15.327 に答える