5

假设我有一个存储在向量中的服务器名称列表,我想一次与他们联系,直到他们成功响应为止。我正在考虑通过以下方式使用 STL 的 find_if 算法:

find_if(serverNames.begin(), serverNames.end(), ContactServer());

其中 ContactServer 是谓词函数对象。
一方面,存在一个问题,因为谓词不会总是为相同的服务器名称返回相同的结果(因为服务器停机时间、网络问题等)。但是,无论使用哪个谓词副本,都将返回相同的结果(谓词没有真实状态),因此在这种情况下,与状态保持谓词的原始问题无关。

你说什么?

4

8 回答 8

4

我想我会去的。

我唯一担心的是它的可读性(以及可维护性)。对我来说,它的内容类似于“查找我可以联系的第一台服务器”,这非常有意义。

您可能想要重命名ContactServer以表明它是一个谓词;CanContactServer? (但后来人们会抱怨隐藏的副作用。嗯......)

于 2008-08-26T09:17:59.637 回答
4

这正是 STL 算法的用途。这根本不是滥用。此外,它的可读性很强。重定向到 null 任何告诉你的人。

于 2008-09-22T04:08:22.953 回答
2

在我看来,这种用法std::find_if有点误导。当我阅读这段代码时,我不希望出现任何副作用,我只是希望找到一个服务器名称。结果被丢弃的事实find_if也让我怀疑代码是否真的正确。也许谓词的另一个名称会使意图更清晰,但我认为问题更根本。

对于大多数人来说,find_if是一种查询算法,而不是一种修改算法。尽管您实际上并没有修改迭代的值,但您正在修改应用程序的全局状态(在这种情况下,您甚至可能修改远程服务器的状态)。

在这种情况下,我可能会坚持使用手动循环,尤其是现在 C++11 引入了基于范围的 for 循环:

for (std::string const & name : serverNames)
{
    if (ContactServer(name)) break;
}

另一种解决方案是将其封装在一个函数中,其名称可以更清楚地传达意图,例如apply_until

template <typename InputIterator, typename Function>
void apply_until(InputIterator first, InputIterator last, Function f)
{
    std::find_if(first, last, f);
    // or
    // while (first != last)
    // {
    //     if (f(*first)) break;
    //
    //     ++first;
    // }
}
}

但也许我过于纯粹了:)!

于 2012-05-25T16:08:05.563 回答
0

std::for_each 可能是一个更好的候选人。

1) 在被复制到每个元素上使用相同的函数对象之后,并且在处理所有元素之后,将可能更新的函数对象的副本返回给用户。

2)在我看来,它也会提高调用的可读性。

函数对象和 for_each 调用看起来像:


struct AttemptServerContact {
  bool        server_contacted;
  std::string active_server;    // name of server contacted

  AttemptServerContact() : server_contacted(false) {}

  void operator()(Server& s) {
    if (!server_contacted) {
      //attempt to contact s
      //if successful, set server_contacted and active_server
    }
  }
};

AttemptServerContact func;
func = std::for_each(serverNames.begin(), serverNames.end(), func);
//func.server_contacted and func.active_server contain server information.
于 2008-09-19T15:50:42.777 回答
0

find_if 似乎是正确的选择。在这种情况下,谓词不是有状态的。

于 2008-09-19T15:52:36.670 回答
0

find_if就是为了这个吗?

但请注意,如果您遍历迭代器,它将找到所有服务器 - 但您不会这样做(根据 OP)。

于 2008-08-26T09:21:00.020 回答
0

但是,无论使用哪个谓词副本,都将返回相同的结果(即谓词没有真实状态),因此在这种情况下,与状态保持谓词的原始问题无关。

那么问题出在哪里?函数对象不一定是有状态的。在这种情况下使用函数对象而不是函数指针实际上是最佳实践,因为编译器更擅长内联它们。在您的情况下,函数对象的实例化和调用可能根本没有开销,因为find_if它是一个函数模板,编译器将为您的仿函数生成一个自己的版本。

另一方面,使用函数指针会导致间接。

于 2008-08-26T09:22:30.797 回答
0

即将发布的 C++ 标准版本中,对于谓词应始终为相同的输入返回相同的值这一事实,我找不到任何明确的限制。我查看了第 25 节(第 7 至第 10 段)。

返回值的方法可能会从一个调用更改为另一个调用,如您的情况,应该是 volatile (从 7.1.6.1/11 开始:“volatile 是对实现的提示,以避免涉及对象的激进优化,因为对象的值可能通过实现无法检测到的方式进行更改”)。

谓词“不应通过取消引用的迭代器应用任何非常量函数”(第 7 和第 8 段)。我认为这意味着他们不需要使用非易失性方法,因此您的用例就标准而言是可以的。

如果措辞是“谓词应该应用 const 函数......”或类似的东西,那么我会得出结论,'const volatile' 函数是不行的。但这种情况并非如此。

于 2008-09-02T11:21:20.067 回答