C++ memcmp与多重相等比较 预条件< /强>:考虑此类类或结构 t>代码>,对于两个对象 < > b>代码>类型 t>代码> memcmp(&a, &b, sizeof(T)) == 0

C++ memcmp与多重相等比较 预条件< /强>:考虑此类类或结构 t>代码>,对于两个对象 < > b>代码>类型 t>代码> memcmp(&a, &b, sizeof(T)) == 0,c++,memcmp,C++,Memcmp,产生的结果与 a.member1 == b.member1 && a.member2 == b.member2 && ... (memberN是T的非静态成员变量) 问题:什么时候应该使用memcmp来比较a和b是否相等,什么时候应该使用链接的=s 下面是一个简单的例子: struct vector { int x, y; }; 要重载向量的运算符==,有两种可能性(如果它们保证给出相同的结果): 或 现在,如果要将新成员添加到vector,例如z

产生的结果与

a.member1 == b.member1 && a.member2 == b.member2 && ...
memberN
T
的非静态成员变量)

问题:什么时候应该使用
memcmp
来比较
a
b
是否相等,什么时候应该使用链接的
=
s


下面是一个简单的例子:

struct vector
{
    int x, y;
};
要重载向量的运算符
==
,有两种可能性(如果它们保证给出相同的结果):


现在,如果要将新成员添加到
vector
,例如
z
组件:

  • 如果使用
    =
    s实现
    运算符==
    ,则必须对其进行修改
  • 如果改为使用
    memcmp
    operator==
    ,则根本不需要修改

但我认为使用chained
==
s可以传达更清晰的含义。虽然对于拥有众多成员的大型
T
memcmp
更具吸引力。此外,与
=
s相比,使用
memcmp
是否有性能改进?如你所说,如果你选择了这样的类型,那么这两个解决方案会产生相同的结果(大概是,你没有间接数据,对齐/填充都是一样的),那么显然你可以使用你喜欢的任何解决方案。 需要考虑的事项:

  • 性能:我怀疑你是否会看到很多差异,但如果你在意的话,一定要衡量一下
  • 安全性:您说这两种解决方案对于您的
    T
    是一样的,但它们是一样的吗?真的吗?在所有系统上?您的
    memcmp
    方法是否可移植?可能不会
  • 清晰性:如果您的先决条件发生了变化,并且您没有对
    memcmp
    的使用进行充分的说明,那么您的程序很可能会崩溃-因此您使其变得脆弱
  • 一致性:假设您在其他地方使用
    =
    ;当然,对于每一个不符合您的前提条件的
    T
    ,您都必须这样做;除非这是对<>代码>代码>的精心优化,否则你可以考虑在程序中坚持单一方法;李>
  • 易用性:当然,很容易从chained
    ==
    中漏掉一个成员,尤其是当您的成员列表不断增加时

  • 如果两种解决方案都是正确的,则选择可读性更强的解决方案。我认为,对于C++程序员来说,=比 MeMCPM/COD>更可读。我甚至会使用
    std::tie
    而不是链接:

    bool operator==(const vector &lhs, const vector &rhs)
    { return std::tie(lhs.x, lhs.y) == std::tie(rhs.x, rhs.y); }
    

    如果有,仅当结构是POD且安全地
    memcmp
    可比较(甚至不是所有数字类型都是…)时,结果是相同的,问题在于可读性和性能

    可读性?我认为这是一个基于观点的问题,但我更喜欢
    操作符==

    性能?
    操作员==
    是一个短路操作员。在这里,您可以对程序进行更多的控制,因为您可以对比较序列进行重新排序

    虽然
    a==b&&c==d
    c==d&&a==b
    在算法逻辑方面是等价的(结果是一样的),但它们在生成的程序集、“背景逻辑”和可能的性能方面是不等价的

    如果你能看到一些要点,你可以影响你的计划

    例如:

    • 如果两个语句产生false的可能性大致相同,那么您需要先使用更便宜的语句,以尽可能跳过更复杂的比较
    • 如果这两个语句的复杂程度大致相同,并且您事先知道
      c==d
      a==b
      更容易出错,那么您应该首先比较
      c
      d
    使用
    operator==
    可以根据问题调整比较顺序,而
    memcmp
    不提供这种自由

    PS:您可能希望对其进行测量,但对于一个包含3个成员的小型结构,MS VS 2013会为
    memcmp
    情况生成稍微复杂的程序集。在这种情况下,我希望
    操作符==
    解决方案具有更高的性能(如果影响可以测量的话)

    -/伊迪丝-

    注意:即使POD结构成员也可以重载
    运算符==

    考虑:

    #include <iostream>
    #include <iomanip>
    
    struct A { int * p; };
    
    bool operator== (A const &a, A const &b) { return *(a.p) == *(b.p); }
    
    struct B { A m; };
    
    bool operator== (B const &a, B const &b) { return a.m == b.m; }
    
    int main()
    {
      int a(1), b(1);
      B x, y;
      x.m.p = &a;
      y.m.p = &b;
      std::cout << std::boolalpha;
      std::cout << (memcmp(&x, &y, sizeof(B)) == 0) << "\n";
      std::cout << (x == y) << "\n";
      return 0;
    }
    

    <>即使所有成员都是基本类型,我更喜欢<代码>运算符==/COD>并将其留给编译器来考虑将比较优化到它认为是优选的任何程序集。

    < P>你强加了一个非常强的条件,即没有填充。(我假设不是在类成员之间,也不是在这些成员内部)。我猜想您也打算排除任何“隐藏的”来自类的内务管理数据。此外,问题本身意味着我们总是比较完全相同类型的对象。在如此强大的条件下,可能无法想出一个反例,使基于
    memcmp
    的比较不同于
    =
    的比较


    出于性能方面的原因,是否值得使用
    memcmp
    。。如果你真的有充分的理由积极优化一些关键的代码,并且分析表明从
    ==
    切换到
    memcmp
    后有了改进,那么一定要继续。但我不会将其作为常规技术使用ique用于编写比较运算符,即使您的类满足要求。

    =
    更好,因为
    memcmp
    比较纯内存数据(比较
    bool operator==(const vector &lhs, const vector &rhs)
    { return std::tie(lhs.x, lhs.y) == std::tie(rhs.x, rhs.y); }
    
    #include <iostream>
    #include <iomanip>
    
    struct A { int * p; };
    
    bool operator== (A const &a, A const &b) { return *(a.p) == *(b.p); }
    
    struct B { A m; };
    
    bool operator== (B const &a, B const &b) { return a.m == b.m; }
    
    int main()
    {
      int a(1), b(1);
      B x, y;
      x.m.p = &a;
      y.m.p = &b;
      std::cout << std::boolalpha;
      std::cout << (memcmp(&x, &y, sizeof(B)) == 0) << "\n";
      std::cout << (x == y) << "\n";
      return 0;
    }
    
    false
    true
    
    template< class Derived >
    struct Relops_from_compare
    {
        friend
        auto operator!=( const Derived& a, const Derived& b )
            -> bool
        { return compare( a, b ) != 0; }
    
        friend
        auto operator<( const Derived& a, const Derived& b )
            -> bool
        { return compare( a, b ) < 0; }
    
        friend
        auto operator<=( const Derived& a, const Derived& b )
            -> bool
        { return compare( a, b ) <= 0; }
    
        friend
        auto operator==( const Derived& a, const Derived& b )
            -> bool
        { return compare( a, b ) == 0; }
    
        friend
        auto operator>=( const Derived& a, const Derived& b )
            -> bool
        { return compare( a, b ) >= 0; }
    
        friend
        auto operator>( const Derived& a, const Derived& b )
            -> bool
        { return compare( a, b ) > 0; }
    };
    
    struct Vector
        : Relops_from_compare< Vector >
    {
        int x, y, z;
    
        // This implementation assumes no overflow occurs.
        friend
        auto compare( const Vector& a, const Vector& b )
            -> int
        {
            if( const auto r = a.x - b.x ) { return r; }
            if( const auto r = a.y - b.y ) { return r; }
            return a.z - b.z;
        }
    
        Vector( const int _x, const int _y, const int _z )
            : x( _x ), y( _y ), z( _z )
        {}
    };
    
    struct Vector
        : Relops_from_compare< Vector >
    {
        int x, y, z;
    
        // This implementation requires that there is no padding.
        // Also, it doesn't deal with negative numbers for < or >.
        friend
        auto compare( const Vector& a, const Vector& b )
            -> int
        {
            static_assert( sizeof( Vector ) == 3*sizeof( x ), "!" );
            return memcmp( &a, &b, sizeof( Vector ) );
        }
    
        Vector( const int _x, const int _y, const int _z )
            : x( _x ), y( _y ), z( _z )
        {}
    };
    
    struct Vector
        : Relops_from_compare< Vector >
    {
        int x, y, z;
    
        friend
        auto compare( const Vector& a, const Vector& b )
            -> int
        {
            if( a.x < b.x ) { return -1; }
            if( a.x > b.x ) { return +1; }
            if( a.y < b.y ) { return -1; }
            if( a.y > b.y ) { return +1; }
            if( a.z < b.z ) { return -1; }
            if( a.z > b.z ) { return +1; }
            return 0;
        }
    
        Vector( const int _x, const int _y, const int _z )
            : x( _x ), y( _y ), z( _z )
        {}
    };
    
    struct Vector
    {
        int x, y, z;
    
        friend
        auto operator<( const Vector& a, const Vector& b )
            -> bool
        {
            using std::tie;
            return tie( a.x, a.y, a.z ) < tie( b.x, b.y, b.z );
        }
    
        friend
        auto operator==( const Vector& a, const Vector& b )
            -> bool
        {
            using std::tie;
            return tie( a.x, a.y, a.z ) == tie( b.x, b.y, b.z );
        }
    
        friend
        auto compare( const Vector& a, const Vector& b )
            -> int
        {
            return (a < b? -1 : a == b? 0 : +1);
        }
    
        Vector( const int _x, const int _y, const int _z )
            : x( _x ), y( _y ), z( _z )
        {}
    };
    
    struct Vector
    {
        int x, y, z;
    
        friend
        auto operator<( const Vector& a, const Vector& b )
            -> bool
        {
            return (
                a.x < b.x ||
                a.x == b.x && (
                    a.y < b.y ||
                    a.y == b.y && (
                        a.z < b.z
                        )
                    )
                );
        }
    
        friend
        auto operator==( const Vector& a, const Vector& b )
            -> bool
        {
            return
                a.x == b.x &&
                a.y == b.y &&
                a.z == b.z;
        }
    
        friend
        auto compare( const Vector& a, const Vector& b )
            -> int
        {
            return (a < b? -1 : a == b? 0 : +1);
        }
    
        Vector( const int _x, const int _y, const int _z )
            : x( _x ), y( _y ), z( _z )
        {}
    };