【问题标题】:Does `std::find()` short circuit?`std::find()` 是否短路?
【发布时间】:2019-12-18 07:50:32
【问题描述】:

假设我有一个std::vector,它的内容是std::strings 和{"a","b","c"}。如果我要执行std::find() 寻找"a",它会在迭代"a" 时停止(即短路)还是继续到最后?

std::vector<std::string> vec;
vec.insert(vec.begin(), "a");
vec.insert(vec.begin(), "b");
vec.insert(vec.begin(), "c");

哪个更快?

std::find(vec.begin(), vec.end(), "a");
std::find(vec.begin(), vec.end(), "c");

【问题讨论】:

  • 是的,为什么不呢? en.cppreference.com/w/cpp/algorithm/find
  • 即使理论上一个实现确实持续到最后,谁会使用它?它会被自然淘汰。
  • 从复杂性要求中没有要求在第一次出现时停止。但典型的实现方式如图所示。

标签: c++ vector iterator c++03


【解决方案1】:

查看std::find的可能实现

template<class InputIt, class T>
constexpr InputIt find(InputIt first, InputIt last, const T& value)
{
    for (; first != last; ++first) {
        if (*first == value) {  // if the condition met
            return first;       // ---> here returns the iterator
        }
    }
    return last;
}

一旦找到匹配项,它将停止迭代。

【讨论】:

  • 值得一提的是first 并不一定意味着容器的begin()。因此,它可用于在第一次命中后进一步搜索。
【解决方案2】:

根据描述here,是的。

返回范围 [first, last) 中满足的第一个元素 具体标准。

复杂性:至多最后 - 谓词的第一次应用

通过查看其可能的实现,声明std::find 使用短路

【讨论】:

    【解决方案3】:

    C++17 标准草案在 [alg.find] 中定义了 std::find 的行为(仅引用了与问题中使用的重载相关的部分):

    template<class InputIterator, class T> InputIterator find(InputIterator first, InputIterator last, const T& value);

    [...]

    返回[first, last) 范围内的第一个迭代器 i 满足以下相应条件:*i == value, [...]。如果没有找到这样的迭代器,则返回 last

    复杂度:最多last - first应用对应谓词。

    以前的标准版本,包括 C++03,包含基本相同的措辞。

    其中任何内容都不能保证以任何特定顺序搜索元素,或者std::find 在找到匹配项后必须停止测试谓词。

    但是,由于函数必须返回满足条件的范围内的 first 迭代器,因此乱序测试没有意义,因为如果找到匹配项,所有先前的迭代器都会无论如何都需要为更早的比赛进行测试。

    一旦找到匹配项,继续应用谓词也是没有意义的,标准只要求应用谓词“至多”,只要范围中有元素。 p>

    因此,std::find 的任何合理顺序实现都会按顺序搜索迭代器范围,并在找到匹配项时返回。如果一个实现没有这样做,用户一注意到就会抱怨。标准库的实现者希望他们的代码尽可能快,而让他们的代码做不必要的工作没有任何好处。

    我想如果一个实现可以使用并行化,如果它知道这不会导致给定类型的数据竞争,并且在这种情况下,搜索可能会检查第一个匹配之外的迭代器。我不知道是否在任何标准库中针对问题中的非并行 std::find 重载实现了类似的功能。

    【讨论】:

      猜你喜欢
      • 2018-05-21
      • 2023-02-16
      • 2012-03-17
      • 2020-06-27
      • 1970-01-01
      相关资源
      最近更新 更多