8

我正在处理一些具有高级接口的低级代码,并且觉得需要比较运算符来对普通旧数据类型(如 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;
}

所以我的问题是,这是一个好方法还是有一些隐藏的恶魔会在开发周期的后期给我带来麻烦,但它现在有点工作。

4

2 回答 2

1

C++14 可用吗?如果是这样,请考虑PFR库,它将结构变成元组

于 2020-02-28T19:28:33.540 回答
0

如评论中所述,此问题是Define generic comparison operator的受限变体。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==返回false逻辑上等效的对象。这是我对 gcc (head-9.0.0) 和 clang (head-8.0.0) 的输出:

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

更新:在 wandbox.org 上运行的常规 new/delete 也会发生这种情况:

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
于 2018-08-22T06:08:25.530 回答