生成是否保证按顺序执行?

时间:2015-10-22 14:17:55

标签: c++ algorithm lambda language-lawyer sequential

我被告知here

  

无法保证生成的顺序=>取决于实施

我查了gcc's implementation of generate

  for (; __first != __last; ++__first)
*__first = __gen();

Visual Studio的实现与此完全相同。这对我来说是一种解脱,因为在generate中使用lambda来读取和写入捕获可能会产生不确定的结果:

int foo[] = {1, 0, 13};
vector<int> bar(3);

generate(bar.begin(), bar.end(), [&]() {
    static auto i = 0;
    static auto total = 0;

    total += foo[i];
    return foo[i] / total;
});

I expect bar包含{1, 0, 0}

如果我被允许不按顺序执行,这甚至可能导致除以0错误。

如果可以通过证明generate需要按顺序执行来回答这个问题,那么我会更容易入睡。

作为一个注释,我知道experimental::parallel::generate不会是连续的。我只是询问generate

2 个答案:

答案 0 :(得分:3)

我对此很感兴趣所以做了一些研究。

本回答的底部是2011年标准相关部分的副本。

您将从std::generate<>的模板声明中看到,迭代器参数必须分别符合ForwardIteratorOutputIterator的概念。

ForwardIterator 不支持随机访问。它只能按顺序读取或写入。 OutputIterator更具限制性 - 其operator*隐含地包含operator++的效果。这是该概念的一个明确特征。

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

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

QED

  

25.3.7生成[alg.generate]

template<class ForwardIterator, class Generator>
void generate(ForwardIterator first, ForwardIterator last,
Generator gen);

template<class OutputIterator, class Size, class Generator>
OutputIterator generate_n(OutputIterator first, Size n, Generator gen);
  

1效果:第一个算法调用函数对象gen和   通过范围内的所有迭代器分配gen的返回值   [第一,最后一个)。第二个算法调用函数对象gen和   通过范围内的所有迭代器分配gen的返回值   [first,first + n)如果n是正数,否则它什么都不做。

     

2   要求:gen不带参数,大小可以转换为   积分型(4.7,12.3)。

     

3返回:generate_n返回第一个+ n   n的非负值和负值的第一个。

     

4复杂性:   完全是最后的 - 第一次,第n次或0次调用gen和赋值,   分别

答案 1 :(得分:1)

以下是关于它的所有标准(25.7.3 / 1):

template<class ForwardIterator, class Generator>
void generate(ForwardIterator first, ForwardIterator last, Generator gen);

template<class OutputIterator, class Size, class Generator>
OutputIterator generate_n(OutputIterator first, Size n, Generator gen);
  

第一个算法调用函数对象   根   并指定返回值   根   通过   范围内的所有迭代器   [第一,最后一个)   。第二种算法调用函数对象   根   并指定返回值   根   通过范围内的所有迭代器   [第一,第一+ n)   如果   ñ   是   积极的,否则它什么都不做。

如您所见,未明确声明迭代器分配必须按顺序完成。