这是实现通用运算符==和运算符的安全方法

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

看到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 ++生成副本构造函数的方式并不完全一致,例如,do执行成员级复制。

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

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

除非您对内存布局,编译器行为有100%的把握,并且您真的不在乎可移植性,并且您确实想获得效率,否则请不要这样做

SOURCE


13
投票

否-例如,如果您有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类型,但其他所有选项均关闭)。

这些都不是可能的或不常见的,但是我认为标准中也没有任何禁止它们的东西。

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

class Foo { char foo; /// three bytes between foo and bar int bar; };


2
投票
这是非常危险的,因为编译器不仅将这些定义用于普通的旧结构,而且还将用于任何类(无论复杂程度如何),而您忘记为其正确定义==<

有一天,它会咬你。


0
投票
很多取决于您对等价的定义。

例如如果您要在类中比较的任何成员都是浮点数。

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

通常,此类数字应与适当的公差进行数字比较。


0
投票
任何包含单个指针的结构或类都会立即使任何有意义的比较失败。这些运算符仅适用于普通旧数据或POD的任何类。另一个回答者正确地指出了浮点数,以防偶数不成立,并填充字节。

简短的答案:如果这是一个聪明的主意,那么该语言将具有默认的复制构造函数/赋值运算符。

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