为什么std :: transform不保证订单(但for_each保证订单)?这是否允许针对性能的技巧实现?

时间:2013-06-28 03:25:50

标签: c++ stl

我只是意识到标准不保证在std::transform中应用函数回调的顺序。并且它不允许回调函数或仿函数有副作用。但同时std::for_each实际上保证了订单。

一个猜测是变换可以使用不保证顺序的高性能算法,但O(N)已经是最好的算法。

那么为什么标准不会使应用回调函数顺序的transform行为为for_each?用户将受益于此保证。

3 个答案:

答案 0 :(得分:3)

直接从标准引用(在末尾复制):

您将从std::transform<>的模板声明中看到输入迭代器参数必须符合InputIterator的概念。

InputIterator是c ++中限制性最强的迭代器概念之一。它不支持任何类型的随机访问。它只能前进。

因此,std :: transform的任何实现都要求迭代器除了被解除引用或前进之外的任何事情都是不正确的。请记住,通过指定InputIterator,标准明确允许使用std::istream_iterator(例如),并且需要std::transform的实现来尊重其中的限制。它必须仅根据InputIterator概念中可用的方法编写。

因此,暗示,此函数的实现必须顺序访问元素(因此按顺序转换值),因为不这样做会破坏接口中隐含的契约

因此标准 (隐式且安静地)保证std::transform按顺序初始化其元素。编写一个格式良好的std::transform实现是不可能的。

  

25.3.4变换[alg.transform]

template<class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator
transform(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op);

template<class InputIterator1, class InputIterator2, class OutputIterator, class BinaryOperation>
OutputIterator
transform(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryOperation binary_op);
  

1效果:通过i范围内的每个迭代器[result,result + (last1 - first1))分配一个等于op(*(first1 + (i - result))binary_op(*(first1 + (i - result)), *(first2 + (i - result)))的新对应值。

     

2要求:op和binary_op不会使迭代器或子范围无效,或修改范围[first1,last1],[first2,first2 +(last1 - first1)]和[result,result +(last1 - first1)中的元素)。

     

3返回:结果+(last1 - first1)。

     

4复杂性:恰好是last1 - op或binary_op的第一个应用程序。

     

5备注:在一元变换的情况下,结果可能等于第一个;在二进制变换的情况下,结果可能等于first1或first2。

答案 1 :(得分:2)

这种非限制性定义允许并行计算。实现可以选择使用多个线程来应用变换函数。另请参阅相关问题:STL algorithms and concurrent programming

将其视为算法中的语义差异(也就是说,它代表程序员的意图,而不仅仅是另一种工具)。使用for_each,您声明需要顺序扫描。使用transform,您声明只需要为容器中的每个项目添加一个函数,但您不关心它将如何完成。

答案 2 :(得分:2)

尽管有一些早期的答案,但我认为可以以并行方式实现std :: transform。例如:

1)顺序获取所有输入。

2)迭代OutputIterator,初始化虚拟对象并保持对每个输出的引用。

3)使用相应的输出迭代器将输入分配给不同的线程,每个线程独立地进行转换。

像这样,迭代器只会在允许的情况下递增。

正如clcto所指出的,另一个实现可以先执行步骤1),然后为所有输出元素创建一个向量,然后使用给定的函数参数并行计算所有这些,然后将它们按顺序写入输出。