оператор перегрузки == для стручков - PullRequest
0 голосов
/ 03 июня 2018

Я работаю над кодом низкого уровня с высокоуровневыми интерфейсами и чувствовал необходимость в операторе сравнения для модульного тестирования простых старых типов данных (например, структуры 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;
}

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

1 Ответ

0 голосов
/ 22 августа 2018

Этот вопрос является ограниченным вариантом Определите универсальный оператор сравнения , как отмечено в комментариях.Пример опасностей и последствий заполнения для предложенного 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== return false для логически эквивалентных объектов.Вот вывод, который я получил как для gcc (head-9.0.0), так и для clang (head-8.0.0):

un.a={true, 5}
x={true, 5}
false

Обновление : это происходит также с обычными новыми/ 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
...