实现operator==和operator是否安全< using std::memcmp?

问题描述 投票:0回答:6

看到这个问题后,我的第一个想法是定义通用等价和关系运算符是微不足道的:

#include <cstring>

template<class T>
bool operator==(const T& a, const T& b) {

    return std::memcmp(&a, &b, sizeof(T)) == 0;

}

template<class T>
bool operator<(const T& a, const T& b) {

    return std::memcmp(&a, &b, sizeof(T)) < 0;

}
然后,

using namespace std::rel_ops
将变得更加有用,因为运算符
==
<
的默认实现将使其完全通用。显然,这不会执行按成员比较,而是按位比较,就好像该类型仅包含 POD 成员一样。这与 C++ 生成复制构造函数的方式并不完全一致,例如,它 do 执行成员复制。

但是我想知道上面的实现是否确实安全。这些结构自然会具有相同的包装、相同的类型,但是填充的内容是否保证相同(例如,用零填充)?有什么原因或情况会导致此方法不起作用吗?

c++ operator-overloading operators comparison-operators memcmp
6个回答
14
投票

不——举个例子,如果你有 T==(float | double | long double),你的

operator==
就无法正常工作。两个 NaN 永远不应该比较相等,即使它们具有相同的位模式(事实上,检测 NaN 的一种常见方法是将数字与其自身进行比较 - 如果它不等于自身,则它是 NaN)。同样,指数中所有位均设置为 0 的两个浮点数的值均为 0.0(准确),无论尾数中的哪些位可能被设置/清除。

您的

operator<
正常工作的机会更小。例如,考虑
std::string
的典型实现,如下所示:

template <class charT>
class string { 
    charT *data;
    size_t length;
    size_t buffer_size;
public:
    // ...
};

通过这种成员排序,您的

operator<
将根据字符串恰好存储其数据的缓冲区的地址进行比较。例如,如果它碰巧首先使用
length
成员编写,则您的比较将使用字符串的长度作为主键。无论如何,它不会根据实际字符串内容进行比较,因为它只会查看
data
指针的值,而不是它指向的任何内容,这才是你真正想要/需要的.

编辑:就填充而言,不要求填充的内容相等。从理论上讲,填充也可能是某种陷阱表示,如果您尝试查看它,它会导致信号、抛出异常或类似的情况。为了避免这种陷阱表示,您需要使用类似于强制转换的方法将其视为

unsigned char
的缓冲区。
memcmp
可能会这样做,但话又说回来,它可能不会......

另请注意,相同类型的对象并不一定意味着使用相同的成员对齐方式。这是一种常见的实现方法,但编译器也完全有可能做一些事情,比如根据它“认为”特定对象将被使用的频率来使用不同的对齐方式,并在对象中包含某种类型的标签(例如,写入第一个填充字节的值),它告诉这个特定实例的对齐方式。同样,它可以通过(例如)地址分隔对象,因此位于偶数地址的对象具有 2 字节对齐,位于四的倍数的地址具有 4 字节对齐,依此类推(这不能是用于 POD 类型,但除此之外,一切皆废)。 这些都不可能也不常见,但我也想不出标准中有任何禁止它们的内容。

永远不要这样做,除非你 100% 确定内存布局、编译器行为,并且你真的不关心可移植性,并且你真的想获得效率

6
投票

来源

即使对于 POD,== 运算符也可能是错误的。这是由于像下面这样的结构对齐,在我的编译器上占用 8 个字节。


4
投票

这是非常危险的,因为编译器不仅会将这些定义用于普通的旧结构,还会用于任何类,无论多么复杂,因为你忘记正确定义 
==

3
投票
<


有一天,它会咬你。
    

很大程度上取决于您对等效性的定义。


0
投票

上述实现可能会将两个双精度数视为不相等,即使它们来自具有相同输入的相同数学计算 - 因为它们可能不会生成完全相同的输出 - 而是两个非常相似的数字。

通常,这些数字应在数值上与适当的容差进行比较。

任何包含单个指针的结构或类将立即失败任何有意义的比较。这些运算符仅适用于任何普通旧数据(POD)类。另一位回答者正确地指出浮点是一种情况,即使这样也不成立,并填充字节。


0
投票

© www.soinside.com 2019 - 2024. All rights reserved.