为什么 std::for_each 迭代器需要一个可复制构造的迭代器
why does std::for_each iterator need a copy constructable iterator
我注意到 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
编辑:请注意,标准根本没有说明 copy-constructor 被调用,它只是表示调用 f 的次数。那么我可以假设根本没有调用 cc 吗?为什么没有指定operator++和operator*和cc的使用,而f的使用是?
您只是成为了规范的牺牲品,该规范在过去几十年中不断演变。 InputIterator
的概念在 move-only 类型或可移动类型的概念出现之前很久就被发明了。
事后看来,我很想声明 InputIterator
不需要可复制。这将与其单次通过行为完美契合。但我也担心这样的改变会带来压倒性的向后兼容性问题。
除了标准中指定的有缺陷的迭代器概念外,大约十年前,为了提供帮助,gcc std::lib (libstdc++) 开始将 "concepts" 强加于诸如InputIterator
在标准算法中。 IE。因为标准说:
Requires: InputIterator
shall satisfy the requirements of an input iterator (24.2.3).
然后 "concept checks" 被插入到需要 InputIterator
满足输入迭代器的所有要求的标准算法中 无论该算法是否实际使用了所有这些要求. 在这种情况下,是概念检查而不是实际算法要求您的迭代器是 CopyConstructible
.
<叹息>
如果您编写自己的 for_each
算法,那么这样做很简单,不需要您的迭代器是 CopyConstructible
或 CopyAssignable
(如果提供了右值迭代器参数):
template <class InputIterator, class Function>
inline
Function
for_each(InputIterator first, InputIterator last, Function f)
{
for (; first != last; ++first)
f(*first);
return f;
}
对于您的用例,我建议您这样做,或者直接编写您自己的循环。
我注意到 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
编辑:请注意,标准根本没有说明 copy-constructor 被调用,它只是表示调用 f 的次数。那么我可以假设根本没有调用 cc 吗?为什么没有指定operator++和operator*和cc的使用,而f的使用是?
您只是成为了规范的牺牲品,该规范在过去几十年中不断演变。 InputIterator
的概念在 move-only 类型或可移动类型的概念出现之前很久就被发明了。
事后看来,我很想声明 InputIterator
不需要可复制。这将与其单次通过行为完美契合。但我也担心这样的改变会带来压倒性的向后兼容性问题。
除了标准中指定的有缺陷的迭代器概念外,大约十年前,为了提供帮助,gcc std::lib (libstdc++) 开始将 "concepts" 强加于诸如InputIterator
在标准算法中。 IE。因为标准说:
Requires:
InputIterator
shall satisfy the requirements of an input iterator (24.2.3).
然后 "concept checks" 被插入到需要 InputIterator
满足输入迭代器的所有要求的标准算法中 无论该算法是否实际使用了所有这些要求. 在这种情况下,是概念检查而不是实际算法要求您的迭代器是 CopyConstructible
.
<叹息>
如果您编写自己的 for_each
算法,那么这样做很简单,不需要您的迭代器是 CopyConstructible
或 CopyAssignable
(如果提供了右值迭代器参数):
template <class InputIterator, class Function>
inline
Function
for_each(InputIterator first, InputIterator last, Function f)
{
for (; first != last; ++first)
f(*first);
return f;
}
对于您的用例,我建议您这样做,或者直接编写您自己的循环。