Побитовые операции и операции, предполагающие представление данных в памяти, не должны выполняться на объектах
Побитовые операции и операции, предполагающие представление данных в памяти, не должны выполняться на объектах.
В 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 используются для любых объектов, содержащих дополняющие данные.
Операторы, содержащие несоответствующие операции, помечаются, а соответствующие объявления классов подсвечиваются. Определения тривиальных классов и классов типовой формы стандартов см. соответственно в пунктах 6 и 7 [класса] стандарта C++.
В качестве исключения Polyspace не помечает операции, которые используют функции C для доступа к битам памяти тривиальных и стандартных объектов компоновки без заполняющих данных. Хотя использование побитовой операции для тривиальных и стандартных классов компоновки без заполняющих данных соответствует этому правилу, это не является хорошей практикой. Вместо этого используйте выделенную функцию-член, перегруженные операторы или мутаторы.
Если вы ожидаете нарушения правила, но не видите его, обратитесь к разделу Нарушения стандартов кодирования не отображаются.
| Группа: Специальные функции-члены |
| Категория: Обязательный, частично автоматизированный |