Побитовое сравнение любой структуры


То, что я пытался сделать, это сравнить произвольных структур независимых от == оператором реализации.

template<typename T>
bool bitWiseCompare(T a, T b)
{
  size_t size = sizeof(T) / sizeof(char);
  char* array_a = (char*)(&a);
  char* array_b = (char*)(&b);
  for(size_t i = 0; i<size; i++)
  {
    if(array_a[i] != array_b[i])
    {
      return false;
    }
  }
  return true;
}


587
6
задан 18 марта 2018 в 09:03 Источник Поделиться
Комментарии
2 ответа

Это сравнение может потерпеть неудачу, если есть какие-то балластом в Tкак эти лишние байты не инициализируется какое-либо определенное значение.

Другой причиной отказа может исходить от наследства. Если один из объектов является частью большего класса (T используется в качестве базового класса) с виртуальными функциями, таблицы vtable указатели могут быть различными, если a и b являются частью различных иерархий классов. Виртуальное наследование базовых классов T может также вызвать проблемы.

sizeof(char) всегда 1, поэтому нет необходимости разделять ее.

Поскольку вы читаете только от ваших параметров, вы должны взять их const &T чтобы избежать ненужных копий.

12
ответ дан 18 марта 2018 в 10:03 Источник Поделиться

На C++ не обязательно, чтобы держаться подальше от таких вещей, как немного сравнений, но лучше делать это в самых очевидных возможных-способом, что я имею в виду, что ваш код должен выглядеть опасным и явным одновременно. У вас есть инструменты для этого в вашем распоряжении: пространства имен, уродливых моделей и алгоритмов:

#include <algorithm>
namespace unsafe {
template <typename T>
constexpr auto begin(const T& item) {
return reinterpret_cast<const char*>(&item);
}
template <typename T>
constexpr auto end(const T& item) {
return reinterpret_cast<const char*>(&item)+sizeof(T);
}
template <typename T>
auto bitwise_equal(const T& lhs, const T& rhs) {
return std::equal(begin(lhs), end(lhs), // will become constexpr with C++20
begin(rhs), end(rhs));
}
}

Так это не будет выглядеть безобидно, когда вы используете его:

int main() {
auto a = 125.5;
std::cout << std::boolalpha << unsafe::bitwise_equal(a, a);
}

Несколько дополнительных замечаний:


  • bitwise_compare не самое точное название для функции, поскольку compare традиционно зарезервированы для функций, возвращающих заказа (-1, 0, 1), а не только равенства.

  • предоставление begin() и end() не надо, так как begin(item)+sizeof(T) как правильно, и, наверное, как читается замену, но из эстетических соображений иногда достаточно

  • std::equal станет constexpr С новым стандартом, это означает, что в C++'S стиль реализация могла бы стать более эффективной, чем memcmp реализация данной компиляции значения.

  • это обычно лучше использовать четыре параметра версии алгоритмов более двух диапазонах; в данном случае оно явно избыточно, поскольку длина двух аргументов по строительству равны, но тогда последовательность является добродетелью.

  • повторное использование algorithmхороший способ избежать стремно, но частые ошибки можно было бы сделать с сырыми петли,

например:

auto  pa = reinterpret_cast<const char*>(&a);
for (auto pb = reinterpret_cast<const char*>(&b); pb != pb+sizeof(T); ++pb) // oops!
// ...

6
ответ дан 19 марта 2018 в 09:03 Источник Поделиться