该代码是否滥用了STL的find_if?
假设我有一个存储在引导程序中的服务器名称列表,我想一次与它们联系一次,直到成功响应为止。我正在考虑通过以下方式使用STL的find_if算法:
find_if(serverNames.begin(), serverNames.end(), ContactServer());
其中ContactServer是谓词功能对象。
一方面,存在一个问题,因为谓词将不会总是针对相同的服务器名称返回相同的结果(由于服务器停机,网络问题等)。但是,无论使用哪个谓词副本(即谓词都没有真实状态),都将返回相同的结果,因此在这种情况下,保持状态谓词的原始问题并不重要。
你怎么说?
解决方案
回答
我想我会去的。
我唯一担心的是它的可读性(以及可维护性)。对我来说,它读的是"找到我可以联系的第一台服务器"之类的东西,这很有意义。
我们可能需要重命名" ContactServer"以表明它是一个谓词。 CanContactServer
? (但是后来人们会抱怨隐藏的副作用。嗯...)
回答
那不是'find_if'的目的吗?
但是请注意,如果迭代迭代器,它将找到所有服务器,但我们不会这样做(根据OP)。
回答
However, the same result will be returned regardless of which copy of the predicate is used (i.e. the predicate has no real state), so the original problem with state-keeping predicates is not relevant in this case.
那么问题出在哪里呢?函数对象不一定必须是有状态的。在这种情况下,实际上最好的方法是使用函数对象而不是函数指针,因为编译器会更好地内联它们。在情况下,函数对象的实例化和调用可能根本没有开销,因为find_if
是函数模板,并且编译器将为函子生成自己的版本。
另一方面,使用函数指针将导致间接调用。
回答
在即将发布的C ++标准版本中,对于谓词对于同一输入应始终返回相同值的事实,我找不到任何明确的限制。我调查了第25节(第7至10段)。
根据情况,返回可能从一个调用更改为另一个调用的值的方法应该是可变的(从7.1.6.1/11:" volatile是实现的一种提示,以避免涉及对象的积极优化,因为对象的值可能通过实现无法检测的方式进行更改")。
谓词"不得通过被取消引用的迭代器应用任何非常数函数"(第7和8段)。我的意思是,不要求他们使用非易失性方法,因此就该标准而言,用例是可以的。
如果措辞是"谓词应应用const函数..."或者类似的内容,那么我将得出结论," const volatile"函数并不可行。但这种情况并非如此。
回答
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.
回答
在这里,find_if似乎是正确的选择。在这种情况下,谓词不是有状态的。
回答
这正是STL算法的目的。这根本不是滥用。此外,它是非常可读的。重定向为null否则告诉任何人。