Я работаю над кодом низкого уровня с интерфейсами высокого уровня и чувствовал необходимость в операторе сравнения для модульного тестирования простых старых типов данных (например, структуры FILETIME), но, поскольку C ++ даже не предоставляет сравнения по элементам, я написал следующее:
template <typename Type>
std::enable_if_t<std::is_pod<Type>::value, bool> operator==(const Type& a,
const Type& b) {
return std::memcmp(&a, &b, sizeof(Type)) == 0;
}
Поэтому мой вопрос в том, хороший ли это способ или есть какие-то скрытые демоны, которые позже доставят мне неприятности на протяжении всего цикла разработки, но пока это работает.
Этот вопрос является ограниченным вариантом Определить универсальный оператор сравнения, как отмечено в комментариях. Пример опасности и влияния заполнения на предложенный operator==
для POD это:
template <typename Type>
std::enable_if_t<std::is_pod<Type>::value, bool> operator==(const Type& a,
const Type& b)
{
return std::memcmp(&a, &b, sizeof(Type)) == 0;
}
struct St {
bool a_bool;
int an_int;
};
union Un {
char buff[sizeof(St)];
St st;
};
std::ostream &operator<<(std::ostream & out, const St& data)
{
return out << '{' << std::boolalpha << data.a_bool << ", " << data.an_int << '}';
}
int main()
{
Un un{{1,2,3,4,5}};
new (&un.st) St;
un.st.a_bool = true;
un.st.an_int = 5;
St x={true, 5};
std::cout << "un.a=" << un.st << '\n';
std::cout << "x=" << x << '\n';
std::cout << (x == un.st) << "\n";
return 0;
}
И то и другое un.st
а также x
содержат те же данные, но un.st
содержит немного мусора в дополненных байтах. Мягкий мусор делает предложение operator==
вернуть false
для логически эквивалентных объектов. Вот вывод, который я получил для gcc (head-9.0.0) и clang (head-8.0.0):
un.a={true, 5}
x={true, 5}
false
Обновить: это происходит также с обычным new / delete, как на wandbox.org:
std::enable_if_t<std::is_pod<Type>::value, bool> operator==(const Type& a,
const Type& b)
{
return std::memcmp(&a, &b, sizeof(Type)) == 0;
}
struct St {
bool a_bool;
int an_int;
};
std::ostream &operator<<(std::ostream & out, const St& data)
{
return out << '{' << std::boolalpha << data.a_bool << ", " << data.an_int << '}';
}
static constexpr unsigned N_ELEMENTS = 2;
int main()
{
{
volatile char * arr = new char[sizeof(St) * N_ELEMENTS];
for (unsigned i=0; i < sizeof(St) * N_ELEMENTS ; ++i)
arr[i] = i + 1;
std::cout << "arr = " << (void*)arr << "\n";
delete[] arr;
}
St * ptr_st = new St[N_ELEMENTS];
std::cout << "ptr_st = " << ptr_st << "\n";
for (unsigned i=0 ; i != N_ELEMENTS; ++i) {
ptr_st[i].a_bool = true;
ptr_st[i].an_int = 5;
}
St x={true, 5};
std::cout << "x=" << x << '\n';
std::cout << "ptr_st[1]=" << ptr_st[1] << '\n';
std::cout << (x == ptr_st[1]) << "\n";
return 0;
}
Для которого вывод:
arr = 0x196dda0
ptr_st = 0x196dda0
x={true, 5}
ptr_st[1]={true, 5}
false
Других решений пока нет …