Нет, это не разрешено C ++.Арифметика указателя определяется только в том случае, если вы остаетесь внутри одного и того же массива (или после его конца).
expr.add # 4
Когда выражение J
с целочисленным типом добавляется или вычитается из выражения P
типа указателя, результат имеет тип P
.
(4.1) Если P
вычисляет нулевое значение указателя, а J
оценивает 0
, результатом является нулевое значение указателя.
(4.2) В противном случае, если P
указывает на элемент x[i]
объекта массива x
с n элементами, выражения P + J
и J + P
(где J
имеет значение j
) указывают на (возможно, гипотетический) элемент x[i+j]
, если 0≤i+j≤n
ивыражение P - J
указывает на (возможно, гипотетический) элемент x[i−j]
, если 0≤i−j≤n
.
(4.3) В противном случае поведение не определено.
(4.1) не применяется, потому что вы не работаете с nullptr
s.(4.2) не применяется, потому что вы работаете с double*
, поэтому x
в стандартной кавычке должно быть массивом double
, то есть членом b
вашей структуры.Оставлять свои границы с помощью арифметики с указателями, в соответствии с оставшимся (4.3), является неопределенным поведением.
То, что вы пытаетесь сделать здесь, это именно то, что хороший компилятор должен (и будет) делать в любом случае:1050 *
volatile double output;
void bar(std::vector<foo> bar, int innerOffset)
{
for (foo& f : bar)
output = f.b[innerOffset];
}
https://godbolt.org/z/S9qkTf
Обратите внимание, как при разборке выполняется арифметика указателей, которую вы хотите (поскольку компилятор знает, что он работает на целевой платформе ).Вот самый внутренний цикл:
.L3:
movsd xmm0, QWORD PTR [rax+24+rsi*8]
add rax, 104
movsd QWORD PTR output[rip], xmm0
cmp rdx, rax
jne .L3
104 байта в точности соответствует размеру foo
.Выражение [rax+24+rsi*8]
выполняет всю дополнительную арифметику указателя бесплатно.