【发布时间】:2015-01-04 09:47:34
【问题描述】:
我注意到 std::for_each 需要它的迭代器来满足 InputIterator 的要求,而 InputIterator 又需要 Iterator 然后是 Copy{Contructable,Assignable}。
这不是唯一的,std::for_each 实际上使用了复制构造函数 (cc)(就我的配置而言不是赋值)。即从迭代器中删除 cc 会导致:
error: use of deleted function ‘some_iterator::some_iterator(const some_iterator&)’
为什么 std::for_each 需要抄送?我发现这特别不方便,因为我创建了一个迭代器,它递归地遍历文件夹中的文件,跟踪队列中的文件和文件夹。这意味着迭代器有一个队列数据成员,如果使用 cc,也必须复制该成员:这是不必要的低效。
奇怪的是在这个简单的例子中没有调用cc:
#include <iostream>
#include <iterator>
#include <algorithm>
class infinite_5_iterator
:
public std::iterator<std::input_iterator_tag, int>
{
public:
infinite_5_iterator() = default;
infinite_5_iterator(infinite_5_iterator const &) {std::cout << "copy constr "; }
infinite_5_iterator &operator=(infinite_5_iterator const &) = delete;
int operator*() { return 5; }
infinite_5_iterator &operator++() { return *this; }
bool operator==(infinite_5_iterator const &) const { return false; }
bool operator!=(infinite_5_iterator const &) const { return true; }
};
int main() {
std::for_each(infinite_5_iterator(), infinite_5_iterator(),
[](int v) {
std::cout << v << ' ';
}
);
}
但是需要编译时间。为什么 std::for_each 需要复制构造迭代器,什么时候完成?这不是非常低效吗?
注意:我说的是迭代器的 cc,而不是它的元素,就像这里所做的那样:unexpected copies with foreach over a map
编辑:请注意,该标准根本没有说明复制构造函数被调用,它只是表达了 f 被调用的次数。那么我可以假设根本没有调用 cc 吗?为什么没有指定使用operator++和operator*和cc,而使用f是?
【问题讨论】:
-
“未调用”。允许编译器优化复制。但是,这并没有改变在某些情况下必须提供复制 ctor 的事实。
-
是的,它是必需的,但不一定要调用。我的问题是,何时/可以调用它。这对for_each的效率很重要,是不是叫做each迭代器?一开始只有一次?它从来没有被调用过吗?此外,为什么它真的需要。我不明白为什么 std::for_each 只能使用引用和前缀++。我可以编写一个迭代迭代器的 for 循环,但不需要 cc 或 ca。这是否意味着 for 循环比 std::for_each 更有效?
-
std::for_each 按值接收其参数。仅此一项就需要一个可访问的 cc,无论对它们施加什么额外要求。
-
我也明白了,我很高兴看到我的编译器在那里应用了复制省略。然而,std::for_each 是否可以更频繁地复制迭代器,甚至每次迭代?考虑一个内部带有向量的迭代器,保持位置的索引。如果每次迭代都复制该迭代器,则迭代元素需要 O(n*n) 而不是 O(n):因此了解 std::for_each 的效率很重要。
-
标准对此只字未提,由实施决定。如果您的迭代器需要大量复制,则可能会导致性能下降。迭代器不应该很重。您可以考虑另一种具有 O(1) 复制的内部簿记数据结构(例如,具有共享节点的基于单链表的堆栈)。