#cpp #language_lawyer
Вопрос 1. В стандарте языка есть такое понятие как similar types (conv.qual/2). Являются ли типы unsigned char и int similar? (Я полагаю, что нет, однако, если да, то хотелось бы узнать почему?) Вопрос 2. В разделе стандарта языка, описывающего аддитивные операции (в частности арифметику указателей), есть интересный пункт expr.add/6: For addition or subtraction, if the expressions P or Q have type “pointer to cv T”, where T and the array element type are not similar, the behavior is undefined. [ Note: In particular, a pointer to a base class cannot be used for pointer arithmetic when the array contains objects of a derived class type. — end note ] Пусть есть следующий код: int mass[2]; unsigned char *p = reinterpret_cast(mass); p = p + 1; //UB? Является ли приведённый код неопределённым поведением? Если нет, то почему? (По-моему, приведённый код в точности соответствует приведённой цитате из стандарта. Этот вопрос возник у меня отчасти потому, что когда речь заходит о strict aliasing rules, то всегда оговаривается, что к объектам можно получить доступ через char/unsigned char. Но о каком доступе к объекту может идти речь, если нельзя наращивать указатель?) Вопрос 3. Если поведение кода в вопросе 2 не определено, то как реализовать свой memcpy?
Ответы
Ответ 1
Речь в [conv.qual] идёт о разложении сложных типов, являющихся указателями или массивами с перемежающими квалификаторами const, volatile. Причём наличие условия n > 0 говорит о том, что эти типы должны быть как минимум второго уровня, условно, указатель на указатель. При всём этом базовый тип U в разложении должен быть одинаковым. Понятно, что базовые типы int и unsigned char таковыми не являются. Немного примеров схожих (similar) и не схожих типов можно посмотреть здесь (раздел Type aliasing). Далее в цитате, которую Вы приводите, упоминается пример, говорящий, что нельзя итерироваться по контейнеру элементов производного типа, имея указатель на базовый тип: struct B {}; struct D : B {}; D a[10]; B* p = a; p++; // породит значение, которое может не указывать на валидный объект типа D Доступ же к объектам через указатель на char, unsigned char или std::byte явно разрешен. То есть проблем с реализацией memcpy не будет.
Комментариев нет:
Отправить комментарий