Побитовые операции и операции, предполагающие представление данных в памяти, не должны выполняться на объектах
Побитовые операции и операции, предполагающие представление данных в памяти, не должны выполняться в отношении объектов.
На C++ представление объекта в памяти может включать:
Представители данных, объявленные с различными привилегиями доступа
Представители данных битового поля
Заполнение байтов между представителями данных
Заполнение байтов в конце представителей данных
Указатели на vtable для поддержки виртуальных функций
Расположение этих различных частей объекта в памяти зависит от окружения. В сложение статические представители данных или представителей функций объекта хранятся в отдельном физическом местоположении в памяти. Когда вы выполняете побитовую операцию над объектом, принимая определенное расположение данных в памяти, вы можете непреднамеренно принять неправильно, и биты доступа не являются частью представления значения объекта. Доступ к этим битам может привести к неопределенному поведению.
Допустим, этот класс, который содержит виртуальную функцию:
class notPOD{ public: virtual void foo(); int value; protected: double dvalue; }; //... int main(){ notPOD Obj; std::memset(&Obj, 57, 2); // attempts to set Obj::value to 57 }
Obj
хранится в блоке памяти, блок содержит указатель на виртуальную таблицу в дополнение к переменным Obj::value
и Obj::dvalue
. Размер этого указателя или его местоположение в памяти могут зависеть от окружения. В main()
, std::memset()
пытается задать значение Obj::value
принимая, что:
Obj::value
является первым блоком в представлении памяти Obj
.
Obj::value
представлен 2 байтами в памяти.
Потому что эти предположения, как правило, не верны, использование std::memset()
может привести к неопределенному поведению. Например, если вы непреднамеренно измените указатель на виртуальную таблицу, вызывая foo()
может вызвать неожиданную функцию.
Представление класса и структур в памяти зависит от среды и может содержать дополнительные байты наряду с представлением значения. Опора на представление данных объекта для выполнения побитовых операций может привести к изменению бит, которые не являются частью представления значения, приводя к неопределенному поведению. Избегайте операций, которые предполагают определенное представление объекта в памяти для доступа к его битам. Чтобы выполнить операции над классом, используйте выделенные функции представителя, перегруженные операторы или мутаторы.
Функции C, которые получают доступ к битам памяти, включают std::memset()
, std::memcpy()
, std::memmove()
, std::strcpy()
, std::memcmp()
, std::strcmp()
. Polyspace® помечает оператор, когда:
Вы используете функции C, чтобы инициализировать или скопировать инициализацию нетривиальных объектов
Вы используете функции C, чтобы сравнить нестандартные объекты размещения
Вы используете функции C для любых объектов, которые содержат данные заполнения
Операторы, содержащие несоответствующие операции, помечены, и соответствующие объявления классов подсвечены. Определения тривиальных и стандартных классов размещения см. в Стандартах C++, [класс], абзацы 6 и 7 соответственно.
В качестве исключения Polyspace не помечает операции, которые используют функции C для доступа к битам памяти тривиальных и стандартных объектов размещения без данных заполнения. Хотя использование побитовой операции на тривиальных и стандартных классах размещения без данных заполнения соответствует этому правилу, это не является хорошей практикой. Вместо этого используйте выделенную функцию представителя, перегруженные операторы или мутаторы.
Если вы ожидаете нарушения правил, но не видите его, обратитесь к разделу «Стандартные нарушения кодирования не отображаются».
Группа: Специальные функции представителей |
Категория: Требуемая, Частично автоматизированная |