草庐IT

c++ - memcmp 与多重相等比较

coder 2023-05-31 原文

前提条件 : 考虑这样一个类或结构 T ,对于两个对象 ab类型 T

memcmp(&a, &b, sizeof(T)) == 0

产生相同的结果
a.member1 == b.member1 && a.member2 == b.member2 && ...

( memberNT 的非静态成员变量)。

问题 : 什么时候应该memcmp用于比较ab为了平等,什么时候应该链接 ==可以使用吗?

这是一个简单的例子:
struct vector
{
    int x, y;
};

重载运算符 ==vector ,有两种可能性(如果它们保证给出相同的结果):
bool operator==(vector lhs, vector rhs)
{ return lhs.x == rhs.x && lhs.y == rhs.y; }

或者
bool operator==(vector lhs, vector rhs)
{ return memcmp(&lhs, &rhs, sizeof(vector)) == 0; }

现在,如果要向 vector 添加新成员,例如 z成分:
  • == s 用于实现 operator== ,必须修改。
  • memcmp改为使用,operator==根本不需要修改。

  • 但我认为使用链式 == s 传达了更清晰的含义。虽然对于大T拥有众多成员(member)memcmp更诱人。此外,使用 memcmp 是否有性能提升?在 == ?还有什么要考虑的吗?

    最佳答案

    关于memcmp的前提与 == 的成员比较产生相同的结果,虽然这个先决条件在实践中经常得到满足,但它有点脆弱。

    理论上,更改编译器或编译器选项可以打破该先决条件。更值得关注的是,代码维护(所有编程工作的 80% 都是维护,IIRC)可以通过添加或删除成员、使类多态、添加自定义 == 来破坏它。重载等。正如其中一条评论中所提到的,前提条件可以适用于静态变量,而不适用于自动变量,然后创建非静态对象的维护工作可以做坏事™。

    以及关于是否使用memcmp的问题或成员(member)==实现 ==运算符对于类,首先,这是一个错误的二分法,因为这些不是唯一的选择。

    例如,就 compare 而言,使用关系运算符重载的自动生成可以减少工作量并且更易于维护。功能。 std::string::compare函数就是这种函数的一个例子。

    其次,选择哪种实现的答案在很大程度上取决于您认为重要的内容,例如:

  • 应该寻求最大化运行效率 , 或
  • 应该寻求创造最清晰的代码 , 或
  • 应该寻求最简洁的,最快写代码,或
  • 应该努力使类(class)最多保险箱 使用,或
  • 别的,也许?

  • 生成关系运算符。

    您可能听说过 CRTP,Curiously Recurring Template Pattern。我记得它是为了处理生成关系运算符重载的需求而发明的。不过,我可能会将其与其他内容混为一谈,但无论如何:
    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; }
    };
    

    鉴于上述支持,我们可以调查可用于您的问题的选项。

    实现A:减法比较。

    这是一个提供全套关系运算符的类,不使用 memcmp== :
    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 )
        {}
    };
    

    实现 B:通过 memcmp 进行比较.

    这是使用 memcmp 实现的同一个类;我想你会同意这段代码可以更好地扩展并且更简单:
    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 )
        {}
    };
    

    实现C:逐个成员比较。

    这是一个使用成员比较的实现。它不强加任何特殊要求或假设。但它更多的是源代码。
    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 )
        {}
    };
    

    实现 D:compare在关系运算符方面。

    这是一种通过实现 compare 来逆转事物自然顺序的实现方式。在 < 方面和 == ,直接提供并按照std::tuple实现比较(使用 std::tie )。
    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 )
        {}
    };
    

    正如给定的,客户端代码使用例如>需要一个 using namespace std::rel_ops; .

    替代方案包括将所有其他运算符添加到上述(更多代码),或使用 CRTP 运算符生成方案,根据 < 实现其他运算符和 = (可能效率低下)。

    实现E:通过手动使用<进行比较和 == .

    这个实现是没有应用任何抽象的结果,只是敲击键盘并直接写机器应该做什么:
    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 )
        {}
    };
    

    选择什么。

    考虑最重要的可能方面的列表,例如安全性、清晰度、效率、简短性,评估上述每种方法。

    然后选择对您来说显然最好的方法,或者看起来同样最好的方法之一。

    指导:为了安全起见,您不会选择方法 A,减法,因为它依赖于对值的假设。请注意,还有选项 B,memcmp , 作为一般情况的实现是不安全的,但仅适用于 ==!= .为了效率,你应该更好 测量 , 以及相关的编译器选项和环境,并记住 Donald Knuth 的格言:“过早的优化是万恶之源”(即花时间在上面可能会适得其反)。

    关于c++ - memcmp 与多重相等比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28858359/

    有关c++ - memcmp 与多重相等比较的更多相关文章

    1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    2. ruby - 使用 `+=` 和 `send` 方法 - 2

      如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

    3. ruby - 如何计算 Liquid 中的变量 +1 - 2

      我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

    4. arrays - Ruby 数组 += vs 推送 - 2

      我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

    5. += 的 Ruby 方法 - 2

      有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

    6. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

      出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

    7. ruby - Ruby 中字符串运算符 + 和 << 的区别 - 2

      我是Ruby和这个网站的新手。下面两个函数是不同的,一个在函数外修改变量,一个不修改。defm1(x)x我想确保我理解正确-当调用m1时,对str的引用被复制并传递给将其视为x的函数。运算符当调用m2时,对str的引用被复制并传递给将其视为x的函数。运算符+创建一个新字符串,赋值x=x+"4"只是将x重定向到新字符串,而原始str变量保持不变。对吧?谢谢 最佳答案 String#+::str+other_str→new_strConcatenation—ReturnsanewStringcontainingother_strconc

    8. ruby - rails 3.2.2(或 3.2.1)+ Postgresql 9.1.3 + Ubuntu 11.10 连接错误 - 2

      我正在使用PostgreSQL9.1.3(x86_64-pc-linux-gnu上的PostgreSQL9.1.3,由gcc-4.6.real(Ubuntu/Linaro4.6.1-9ubuntu3)4.6.1,64位编译)和在ubuntu11.10上运行3.2.2或3.2.1。现在,我可以使用以下命令连接PostgreSQLsupostgres输入密码我可以看到postgres=#我将以下详细信息放在我的config/database.yml中并执行“railsdb”,它工作正常。开发:adapter:postgresqlencoding:utf8reconnect:falsedat

    9. ruby - 在 Ruby + Chef 中检查现有目录失败 - 2

      这是我在ChefRecipe中的一blockRuby:#ifdatadirdoesn'texist,moveoverthedefaultoneif!File.exist?("/vol/postgres/data")execute"mv/var/lib/postgresql/9.1/main/vol/postgres/data"end结果是:Executingmv/var/lib/postgresql/9.1/main/vol/postgres/datamv:inter-devicemovefailed:`/var/lib/postgresql/9.1/main'to`/vol/post

    10. ruby-on-rails - 使用 Pow 作为服务器在 RubyMine 中调试 - Ruby 2.1.1 + Rails 4 - 2

      我已经开始使用RubyMine6。我正在处理Rails4、Ruby2.1.1项目。我无法找到如何使用Pow作为服务器调试到RubyMine。你能给我指明正确的方向吗? 最佳答案 我能够使用远程调试从RubyMine进行调试。我正在使用RubyMine6、Rails3、Ruby2.1.1。首先创建一个.powenv文件并添加:exportRUBY_DEBUG_PORT=1234exportPOW_WORKERS=1将以下gem添加到您的Gemfile:gem'ruby-debug-ide'gem'debase'创建一个新的初始化器st

    随机推荐