这是实现泛型运算符==和运算符<?的安全方法吗?

Jon*_*rdy 12 c++ operator-overloading operators

在看到这个问题之后,我首先想到的是定义泛型等价和关系运算符是微不足道的:

#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;

}
Run Code Online (Sandbox Code Playgroud)

using namespace std::rel_ops然后将变得更加有用,因为它的是由运营商的默认实现完全通用的==<.显然,这不执行成员比较,而是执行逐位比较,就好像类型仅包含POD成员一样.这是不是与C++如何生成的拷贝构造函数,例如,这是完全一致的执行成员逐一复制.

但我想知道上述实施是否确实安全.结构自然会具有相同的包装,具有相同的类型,但是填充的内容保证是相同的(例如,用零填充)?是否有任何理由或情况不起作用?

Jer*_*fin 13

不 - 只是例如,如果你有T ==(浮动|双|长双),你的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:
    // ...
};
Run Code Online (Sandbox Code Playgroud)

通过成员的这种排序,您operator<将根据字符串碰巧存储其数据的缓冲区的地址进行比较.例如,如果它恰好是先用length成员编写的,那么您的比较将使用字符串的长度作为主键.在任何情况下,它都不会根据实际的字符串内容进行比较,因为它只会查看data指针的值,而不是它指向的是什么,这是你真正想要/需要的.

编辑:就填充而言,不要求填充内容相等.理论上,填充也可能是某种陷阱表示,如果您甚至试图查看它,它将导致信号,抛出异常或该命令中的某些内容.为了避免这种陷阱表示,你需要使用类似转换的东西来将它看作unsigned chars 的缓冲区.memcmp可能会那样做,但话又说回来......

还要注意的是同一类型的对象也并不一定意味着各成员使用相同的对齐方式.这是一种常见的实现方法,但是编译器完全有可能根据它"使用"特定对象的频率使用不同的对齐来执行某些操作,并对象中包含某种标记(例如,写入第一个填充字节的值,它告诉该特定实例的对齐.同样,它可以通过(例如)地址隔离对象,因此位于偶数地址的对象具有2字节对齐,在4的倍数的地址处具有4字节对齐,依此类推(这不可能是用于POD类型,但除此之外,所有投注均已关闭).

这些都不可能或不常见,但我无法想到禁止它们的标准中的任何内容.