Не читайте padding-биты объекта
Не обращайтесь к битам представления объекта, которые не входят в представление его значения. Или, другими словами, не работайте с объектом как с сырыми байтами (memcmp, memset, хеширование, сериализация), если не все биты его представления участвуют в представлении значения. Сравнивайте и копируйте поля, а не байты.
Представлением объекта типа T является последовательность N байтов (unsigned char) в памяти, где N = sizeof(T). Представлением значения объекта T является является множество битов, в которых хранится значение типа T.
Проблема может заключаться в заполняющих (padding) битах, содержимое которых может быть неопределено.
Неправильно:
#include <cstring>
struct S {
char c;
// padding в 3 байта
int i;
};
bool equal(const S& a, const S& b) {
return std::memcmp(&a, &b, sizeof(S)) == 0;
}
Правильно:
В С++20:
Та же проблема возникает с неиспользуемыми битами в блоке размещения битовых полей.
Неправильно:
#include <cstring>
struct Flags {
unsigned a : 3;
unsigned b : 3;
// остальные биты единицы размещения не входят в представление значения
};
bool equal(const Flags& x, const Flags& y) {
return std::memcmp(&x, &y, sizeof(Flags)) == 0;
}
Правильно:
У полиморфных классов в объекте есть vptr - указатель на таблицу виртуальных функций. Он входит в представление объекта, но не в представление значения: значение определяется значениями членов и динамическим типом. Поэтому важно правильно сравнивать/хешировать/сериализовать сырые байты.
Неправильно: