строка s; & S + 1; Правовой? UB? - PullRequest
5 голосов
/ 09 марта 2010

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

#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-го элемента массива в стиле C string s. Пока мы только оцениваем этот указатель и никогда не разыменовываем его, мы в порядке. Мы можем даже сравнить его с другими указателями на равенство. 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 также является массивом?

Ответы [ 2 ]

12 голосов
/ 09 марта 2010

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

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

5 голосов
/ 09 марта 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...