строка ы;&s+1;Законный?УБ?
-
18-09-2019 - |
Вопрос
Рассмотрим следующий код:
#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
это тоже массив?
Решение
Наличие указателя на "единицу после конца" массива является законным, а не UB, и любой отдельный объект может обрабатываться так, как если бы он находился в массиве длиной 1;однако вам необходимо использовать ptr + 1
вместо этого из-за технических сложностей &ptr[1]
разыменование, а затем получение адреса.Это также относится к &array[size]
становление array + size
.
То, что у вас есть, будет работать так, как вы ожидаете, на всех платформах, о которых я знаю, но, учитывая, насколько легко использовать однозначно правильную форму, я не вижу причин не делать этого вместо этого.
Другие советы
Стандарт C ++ в разделе 5.6 / 4 "Аддитивные операторы" гласит:
Для целей этих операторов указатель на объект, не являющийся массивом, ведет себя так же, как указатель на первый элемент массива длиной один с типом объекта в качестве типа его элемента.
Стандарт C99 6.5.6 / 7 гласит по существу то же самое.