c++ - 这是实现通用 operator== 和 operator< 的安全方法吗?

标签 c++ operators operator-overloading

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

#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++ 生成复制构造函数的方式并不完全一致,例如,确实执行成员复制。

但是我想知道上面的实现是否真的安全。这些结构自然会有相同的填充,属于相同的类型,但是填充的内容是否保证相同(例如,填充为零)?有什么原因或在什么情况下这不起作用?

最佳答案

不——举个例子,如果你有 T==(float | double | long double),你的 operator==不能正常工作。两个 NaN 永远不应该比较为相等,即使它们具有相同的位模式(事实上,检测 NaN 的一种常用方法是将数字与其自身进行比较——如果它不等于自身,则它是 NaN)。同样,两个指数中所有位都设置为 0 的 float 具有值 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可能会那样做,但又可能不会......

另请注意,相同类型的对象并不必然意味着使用相同的成员对齐方式。这是一种常见的实现方法,但编译器也完全有可能根据它“认为”特定对象的使用频率来使用不同的对齐方式,并在 in 表示此特定实例对齐方式的对象(例如,写入第一个填充字节的值)。同样,它可以按(例如)地址分隔对象,因此位于偶数地址的对象具有 2 字节对齐,位于四的倍数的地址具有 4 字节对齐,依此类推(这不能用于 POD 类型,但除此之外,所有投注均无效)。

这些都不太可能也不常见,但我也想不出标准中有任何禁止它们的地方。

关于c++ - 这是实现通用 operator== 和 operator< 的安全方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3610065/

相关文章:

javascript - 在 JavaScript 比较中应该使用哪个等号运算符(== vs ===)?

c++ - 运算符 << 重载的解释

python - Python中不同类型操作数的重载运算符

c++ - 如何在我的 Haxe/hxcpp 构建中包含 libsqlite3?

c++ - 是否可以确保模板类大小始终为 2 ^ N?

C++ 私有(private)数组访问

c++ - 使用 std::list 存储顶点并使用 SFML 绘制它们

c++ - C++ 类中的运算符

perl - 使用双重否定(!!)

c++ - 在 C++ 迭代器中,我应该同时定义 operator== 和 operator!= 吗?