【问题标题】:Equality evaluation in associative containers (STL)关联容器 (STL) 中的平等评估
【发布时间】:2011-11-21 19:44:20
【问题描述】:

我知道 STL 关联容器(以及我猜想的其他正在排序的容器)使用排序标准来测试相等性。

容器的排序标准默认为 st::less,因此会对容器进行相等性测试:

if (! (lhs < rhs || rhs < lhs))

或类似的东西。我对此有几个问题...

首先,比较相等性似乎是一种非常低效的方法——为什么 STL 会这样做?我本来希望 STL 容器只采用一个额外的默认参数来表示相等。

我的第二个问题更多的是关于上面 if 语句的评估。在 C++ 中,该语句中有多少会被评估(lhs > rhs)是真的?在评估失败的一方从而节省一些效率后,它会停止尝试吗?如果是,首先计算表达式的哪一部分?

【问题讨论】:

  • 这是等价,不是等价...
  • @K-ballo 有什么区别?

标签: c++ stl


【解决方案1】:

在“Effective STL”中,Scott Meyers 在第 19 条中对此进行了广泛讨论:

了解相等和等价的区别。

平等,如您所料,基于operator==

等价“基于对象值在排序范围内的相对排序...如果在c 的容器中,两个对象在容器c 中都没有在另一个之前排序顺序。”

迈耶斯是这样表达的:

!( w1 < w2 ) // it's not true that w1 < w2
&&           // and
!( w2 < w1 ) // it's not true that w2 < w1

迈耶斯随后重申:

这是有道理的:两个值是等价的(相对于某些 排序标准)如果两者都不在另一个之前(根据那个 标准。)

至于为什么STL会这样:

仅使用一个比较函数并采用 作为“相同”含义的仲裁者的等价性 标准关联容器...避免那种混淆 将产生于混合使用平等和等价 标准关联容器。

请自己阅读第 19 条(跨越 6 页的大部分内容)以了解全部内容。

【讨论】:

  • "这是有道理的:如果两个值都不在另一个之前(根据该标准),则两个值是等价的(就某些排序标准而言)。" 不,这是有道理的,因为使用排序容器的要求是它有意义
  • 你因为引用 Scott Meyers 的话而对我投了反对票?
  • 没错。 “这是有道理的: ...”是没有意义的,并且可能具有误导性。
  • 他在说为什么用!(w1&lt;w2) &amp;&amp; !(w2&lt;w1)表示等价;他的“这是有道理的”陈述就是指这一点。
  • @curiousguy:别介意那个评论。 strict weak ordering requirement(另见 C++ 标准,我不能引用它的诗句和章节)本身就产生了等价关系:那些 xy既不是 x y 也不是 y x,正是 Meyers 给出的。
【解决方案2】:

STL 关联容器

您的意思是:标准 C++ 排序的关联容器。

我本来希望 STL 容器只使用一个额外的默认参数来表示相等。

那会实现什么?在您的教科书红黑树算法中,而不是

if (x < y)
    // ...
else if (y < x)
    // ...
else
    // equality

你应该有

if (x == y)
    // equality
else if (x < y)
    // ...
else
    // y < x

所以在最坏的情况下仍然是两个比较。

对 cme​​ts 的回答是:仅提供一个小于运算符使容器更易于使用,因为不需要保持小于和等于之间的一致性。假设您有一个存储浮点数的程序。有一天,有人决定通过近似比较替换位相等的float_equals 函数,该函数恰好被某个容器以及它们的代码使用。如果那个人没有更新float_less 函数,因为他们的代码没有使用那个函数,那么你的容器代码就会神秘地中断。

(哦,在显示的示例代码中,一如既往地适用短路。)

【讨论】:

  • 这消除了如果小于和相等运算符不同意 100% 时可能出现的细微错误。
  • "这消除了如果小于和相等运算符没有 100% 一致时可能出现的细微错误。" 如果小于运算符会产生细微错误不同意自己。 ;)
  • @MarkRansom:非常正确,将其添加到答案中。
【解决方案3】:

关于第二个问题:适用于布尔表达式的标准 C 惰性求值规则。如果|| 的 LHS 为真,则不评估 RHS。

【讨论】:

    【解决方案4】:

    C++ 使用 || 从左到右评估 if()。评估左侧(lhs

    【讨论】:

    • "C++ 从左到右计算 if()。" 错误。只有a &amp;&amp; ba || ba, ba ? b : c 是从左到右评估的。
    • 您说得不对,先生。一种 ? b : c 从右到左求值。另外,我指的是他的 || 确实以左侧然后右侧的方式进行评估。
    • "你错了,先生。a ? b : c 从右到左计算" 你是什么意思?根据您的评估,a、b 和 c 的顺序是什么? “i 指的是他的 ||,它确实是以左侧然后右侧的方式进行评估的。”以一种潜在的非常误导方式。
    • ScarletAmaranth,你有权承认自己错了。
    【解决方案5】:

    首先,这似乎是一种非常低效的平等比较方式

    是的,但是排序容器很少做这个测试。

    使用像strcmp 这样的比较函数会更好。同时使用小于和比较会更好。

    在 C++ 中,该语句将被评估 (lhs > rhs) 有多少是正确的?

    在 C 和 C++ 中,a &amp;&amp; ba || ba, ba ? b : c 从左到右进行评估,仅评估有用的右侧部分(重载除外&amp;&amp;||, C++ 中的运算符)。

    这允许几个有用的简短测试,例如:p != NULL &amp;&amp; *p &gt; 2

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-07
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 1970-01-01
      • 2015-06-06
      • 2011-09-18
      • 1970-01-01
      相关资源
      最近更新 更多