Можно ли игнорировать пустого наследника при арифметике указателей?
1,00
р.
р.
Есть класс A, от которого наследуется класс B. Однако, класс B не содержит никаких полей. Если я создам массив элементов B, но использую его как массив элементов A, то будет ли это корректно? В стандарте говорится, что это разрешено только с подобными типами: When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x[i] of an array object x with n elements,86 the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x [ i + j ] if 0 ≤ i + j ≤ n otherwise, the behavior is undefined. Likewise, the expression P - J points to the (possibly-hypothetical) element x [ i − j ] if 0 ≤ i − j ≤ n otherwise, the behavior is undefined. Подобность типов описана рядом, но я не могу понять, являются ли в моём случае типы подобными. Какие именно типы считаются подобными? Вот пример кода: https://ideone.com/ncRepZ https://ideone.com/nMvJ0r Содержит ли он неопределённое поведение? #include using namespace std struct A { int x A(int x) : x(x) {} virtual ~A() {} } struct B : A { B() : A(7) {} } int main() { A *a = new B[4] for (size_t q=0 q<4 ++q) cout << q << ": " << a[q].x << endl <br> delete [] a return 0 } В случае, если это всё-таки не разрешено, достаточно ли добавить проверку на равенство размеров этих двух типов https://ideone.com/iSkJk0 static_assert(sizeof (A) == sizeof (B), "B must have same size as A") чтобы гарантировать, что если программа компилируется, то она не содержит UB?
Ответ По второй ссылке ясно написано, что типы подобны, если они совпадают с точностью до const и volatile, а также замены массива фиксированного размера на массив неизвестного размера: Two types T1 and T2 are similar if they have cv-decompositions with the same n such that corresponding Pi components are either the same or one is “array of Ni” and the other is “array of unknown bound of”, and the types denoted by U are the same. Преобразования между наследником и базовым типом в отношение подобия не входят. Так что формально так делать нельзя, будет UB. На практике проявиться это UB может так же, как и любое другое нарушение strict aliasing rule: A *a = new B[4] a[1].x = 5 B *b = (B*)a (b+1)->x = 6 std::cout << a[1].x << std::endl // Слишком умный компилятор выведет 5 <br>