C++ 如何比较POD类型的对象

C++ 如何比较POD类型的对象,c++,C++,这个例子: #include <iostream> #include <cstring> struct A { int a; bool b; }; bool foo( const A a1, const A a2 ) { return ( 0 == std::memcmp( &a1, &a2, sizeof( A ) ) ); } int main() { A a1 = A(); a1.a = 5;a1.b

这个例子:

#include <iostream>
#include <cstring>

struct A
{
    int  a;
    bool b;
};

bool foo( const A a1, const A a2 )
{
    return ( 0 == std::memcmp( &a1, &a2, sizeof( A ) ) );
}

int main()
{
    A a1 = A();
    a1.a = 5;a1.b = true;
    A a2 = A();
    a2.a = 5;a2.b = true;

    std::cout<<std::boolalpha << foo( a1, a2 ) << std::endl;
}
然后它在我的系统上工作正常(输出为
true


我还可以做些什么来解决上述问题(获取
true
输出)?

由于结构中存在填充,第一个问题无法工作。填充对两个对象具有不同的位模式

如果在使用对象之前使用
memset
设置对象中的所有位,则它将工作:

A a1;
std::memset(&a1, 0, sizeof(A));
a1.a = 5;a1.b = true;

A a2;
std::memset(&a2, 0, sizeof(A));
a2.a = 5;a2.b = true;
在线演示:

  • (您编写的原始代码)
  • (我的修改)


顺便说一下,您可以编写
操作符,因为C++11可以使用元组进行简单的POD比较(在C++14及更高版本中,元组对
=
使用字典比较。您可以使用此库:提取POD的成员类型。然后您可以编写通用比较运算符,它不需要原始对象的memsetting内存来擦除填充,如下所示:

#include "boost/pfr/precise.hpp"
template<typename T>
void foo(const T& a, const T& b)
{
    return boost::pfr::flat_less<T>{}(a, b);
}
#包括“boost/pfr/precise.hpp”
模板
无效foo(施工T&a、施工T&b)
{
返回升压::pfr::平坦的{}(a,b);
}
这种方法的优点是不修改创建对象的代码(当对象不在您的控制之下时,这些代码可能很有价值),但它也会生成额外的二进制代码,并且使用PFR库进行编译会更慢

尽管如此,它仍然是最灵活和干净的,因为简单的memcmp并没有给您真正的语义能力(例如,当您在pod的子类型上使用自定义比较运算符时)


PS:使用PFR库,您可以对POD执行多种其他操作,例如打印它们、迭代成员等。请查看更多示例:


aa1=A();
aa1;std::memset(&a1,0,sizeof(A));
相同。我可以为POD编写运算符,但我无法访问进行比较的函数,因此我只能使用std::memcmp@VJo:否。它不同于
aa1=A()
仅初始化成员,而不是填充。也就是说,
aa1=A()
相当于
aa1;memset(&a1.A,0,sizeof(a1.A));memset(&a1.b,0,sizeof(a1.b));
。剩余的
(sizeof(A)-sizeof(a1.A)-sizeof(a1.b))
字节保持不变,包含垃圾。严格地说,
aa1=A()
不能保证初始化填充,但它仍然可以初始化填充。为什么要通过
const
值而不是
const&
?=>
foo(const A a1,const A a2);
@iammilind
foo
函数来自第三方库,我无权更改其签名您是否尝试过打包该结构,因为您似乎可以控制它?这样您可能不必使用memset“技巧”。VS:
\pragma pack(1)
就在结构之前。G++相同。@RedX我没有,但我会试试。谢谢链接(我不知道有这样的库)你提到它真的很好。我注意到这个库允许你比较和打印结构。你能用例子(像这样)补充你的答案吗为了让你的答案真的很棒?@DenisSablukov:我将添加到示例的链接,因为这超出了这个问题的范围,但肯定是;)。顺便说一句,我刚刚注意到它不需要C++17,14就足够了。
#include <iostream>
#include <tuple>

struct Point {
    int x;
    int y;
    int z;    
};


auto pointToTuple(const Point& p) {
    return std::make_tuple(p.x, p.y, p.z);
}

bool operator==(const Point& lhs, const Point& rhs ) {
    return pointToTuple(lhs) == pointToTuple(rhs);
}

bool operator<(const Point& lhs, const Point& rhs ) {
    return pointToTuple(lhs) < pointToTuple(rhs);
}

int main()
{

    Point a{1, 2, 3};
    Point b{1, 2, 3};
    Point c{2, 2, 2};

    std::cout << (pointToTuple(a) == pointToTuple(b) ? "true" : "false") << "\n"; //true
    std::cout << (pointToTuple(a) == pointToTuple(c) ? "true" : "false") << "\n"; //false

    std::cout << (a == b ? "true" : "false") << "\n"; //true
    std::cout << (a == c ? "true" : "false") << "\n"; //false

    std::cout << (a < b ? "true" : "false") << "\n"; //false
    std::cout << (a < c ? "true" : "false") << "\n"; //true

}
struct Point {
    int x;
    int y;
    int z;    

    auto operator<=>(const Point&) const = default;
};
#include "boost/pfr/precise.hpp"
template<typename T>
void foo(const T& a, const T& b)
{
    return boost::pfr::flat_less<T>{}(a, b);
}