строка с; &с+1; Юридический? УБ?

Рассмотрим следующий код:

#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] указывает на то, чего не существует; шестой элемент в массиве. В приведенном выше коде есть еще один пример: myVec.end(), который указывает на один конец вектора myVec. Совершенно законно взять адрес несуществующего элемента. Мы знаем размер string, поэтому мы знаем, куда должен указывать адрес 6-го элемента массива strings в стиле C. Пока мы только оцениваем этот указатель и никогда не разыменовываем его, все в порядке. Мы даже можем сравнить его с другими указателями на равенство. STL делает это все время в алгоритмах, которые работают с рядом итераторов. Итератор end() указывает на конец, и циклы продолжают повторяться, пока счетчик != 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 также является массивом?


person John Dibling    schedule 08.03.2010    source источник


Ответы (2)


Допустимо, а не UB, иметь указатель на «один после конца» массива, и любой отдельный объект можно рассматривать так, как если бы он находился в массиве длины 1; однако вместо этого вам нужно использовать ptr + 1 из-за технических особенностей &ptr[1] разыменования и последующего получения адреса. Это также относится к тому, что &array[size] становится array + size.

То, что у вас есть, будет работать, как вы ожидаете, на всех платформах, о которых я знаю, но, учитывая, насколько легко использовать однозначно правильную форму, я не вижу причин не делать это вместо этого.

person Community    schedule 08.03.2010
comment
+1 за техническую точность. Это не только легко сделать правильно, но и избежать дальнейших ловушек с перегрузкой operator& (да, перегружать ее плохо. Но это показывает, как можно просто перетаскивать зависимости). Лучше избегать неопределенного поведения. - person Johannes Schaub - litb; 09.03.2010

Стандарт С++ в 5.6/4 «Аддитивные операторы» гласит:

Для целей этих операторов указатель на объект, не являющийся массивом, ведет себя так же, как указатель на первый элемент массива длины один с типом объекта в качестве типа его элемента.

Стандарт C99 6.5.6/7 говорит практически то же самое.

person Michael Burr    schedule 08.03.2010