【问题标题】:What does it mean "Predicates should not modify their state due to a function call"?“谓词不应因函数调用而修改其状态”是什么意思?
【发布时间】:2019-08-13 18:13:12
【问题描述】:

我在网上阅读了有关 C++ 的内容并看到了这样的说法:

谓词不应因函数调用而修改其状态。

我不明白这里的“状态”是什么意思。有人可以举个例子吗?

【问题讨论】:

  • 传递给函数的谓词对象可能被复制任意次数(例如递归快速排序)。如果它们的比较操作(函数调用)改变了它们的状态,每个谓词都会得到不同的状态。

标签: c++ c++11 stl predicate


【解决方案1】:

让我们以算法std::count_if 为例。它遍历一个范围并计算给定谓词评估为真的频率。进一步假设我们要检查容器中有多少元素小于给定数字,例如5 或 15。

谓词可以是很多东西。它必须是可调用的。它可以是函子:

struct check_if_smaller {
    int x;
    bool operator()(int y) const { return y < x; }
};

您可以创建该谓词的不同实例,例如这两个

check_if_smaller a{5};
check_if_smaller b{15};

可用于检查数字是否分别小于515

bool test1 = a(3);  // true because 3 < 5
bool test2 = b(20); // false because 20 is not < 15

成员x 是谓词的状态。通常,当应用谓词时(通过调用其operator()),这不应该改变。

来自wikipedia

在数理逻辑中,谓词通常被理解为 布尔值函数 P: X→ {true, false},称为谓词 十、然而,谓词有许多不同的用途和解释 数学和逻辑,以及它们的精确定义、意义和用途 因理论而异。

粗略地说,谓词是将某物映射到布尔值的函数。我们使用的函子不仅仅是一个函数,而是一个具有状态的函数对象这一事实可以被视为实现细节,并且对于相同的输入重复评估相同的谓词通常会产生相同的结果。此外,算法会做出这种假设,并且没有什么能真正阻止它们复制您传递的谓词(实际上是the standard explicitly permits them to do so)。如果评估谓词会改变其内部状态,则算法可能无法按预期工作。

【讨论】:

  • 您的意思是任何人都应该避免在谓词执行时更改 x,对吧?是否可以将 x 设为私有并使用 setX(...) 方法来控制一切?
  • @Gupta a 模拟谓词“检查一个数字是否小于 5”。如果您更改其 x 成员,则它是一个不同的谓词。当然,您可以将 x 设为私有,但我不明白这有什么不同或有什么优势
  • 我还建议使谓词函数调用运算符const,如果它不修改它的状态:bool operator()(int y) const { return y &lt; x; }
  • @DanielLangr 太棒了,我会把它编辑成答案,只是现在没有时间
【解决方案2】:

用外行的话来说,谓词中的一个状态是一个数据成员。更改状态的谓词意味着成员在算法执行期间发生了变化,并且该更改将影响谓词行为。

避免这种情况的原因是算法没有义务保留谓词的单个实例。它们可能很容易被复制,并且在一个副本中更改了状态,不会与另一个副本中的状态共享。结果,程序将出现意外行为(对于期望状态更改生效的人)。

【讨论】:

    【解决方案3】:

    基本上什么标准说谓词应该像纯函数一样(在数学术语中),即它的返回值应该仅取决于输入。

    之所以提到状态,是因为谓词可以被复制或可以在不同的线程中调用,这取决于实现和平台行为。对于非函数的 lambda 和其他可调用对象,这可能意味着对存储的无序访问、通过引用捕获或访问不同的值(如果它们是按值捕获的)。对于一个函数来说,这意味着任何副作用(包括静态变量的变化)都可能导致问题。

    如果排序谓词对同一对返回不同的结果,则某些排序算法将无效。

    【讨论】:

      【解决方案4】:

      除了其他答案之外,许多采用谓词的算法不承诺任何特定的遍历顺序(ExecutionPolicy 重载允许交错遍历)。对于同一个问题,您可能会得到不同的答案。

      如果有多个线程调用1谓词并且它改变了一些共享值,那就是a data race,即未定义的行为。

      1. 或一个线程交错调用

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-29
        • 2011-06-02
        • 2015-02-21
        相关资源
        最近更新 更多