迭代器旨在提供对指针的抽象。
例如,递增迭代器始终会操纵迭代器,以便如果集合中有下一项,则它引用该下一项。如果它已经引用了集合中的最后一项,则在增量之后它将是一个无法取消引用的唯一值,但将与另一个迭代器进行比较,该迭代器指向同一个集合末尾之后的一个迭代器(通常使用 获得collection.end()
) .
在将迭代器插入字符串(或向量)的特定情况下,指针提供了迭代器所需的所有功能,因此指针可以用作迭代器而不会丢失所需的功能。
例如,您可以使用std::sort
对字符串或向量中的项目进行排序。由于指针提供了所需的功能,因此您还可以使用它来对本机(C 样式)数组中的项目进行排序。
同时,是的,定义(或使用)与指针分离的迭代器可以提供并非严格要求的额外功能。例如,一些迭代器至少提供某种程度的检查,以确保(例如)当您比较两个迭代器时,它们都是同一个集合的迭代器,并且您没有尝试越界访问。原始指针不能(或至少通常不会)提供这种能力。
这在很大程度上回到了“不要为你不使用的东西买单”的心态。如果您真的只需要并且想要本机指针的功能,它们可以用作迭代器,并且您通常会获得与直接操作指针所获得的代码基本相同的代码。同时,对于您确实需要额外功能的情况,例如遍历线程 RB-tree 或 B+ 树而不是简单数组,迭代器允许您在保持单一、简单接口的同时做到这一点。同样,对于您不介意为额外安全支付额外费用(在存储和/或运行时间方面)的情况,您也可以得到它(并且它与单个算法之类的东西解耦,因此您可以在哪里得到它您想要它而不会被迫在其他地方使用它,例如,
在我看来,很多人在谈到迭代器时有点忽略了这一点。许多人愉快地重写了类似的东西:
for (size_t i=0; i<s.size(); i++)
......变成这样的东西:
for (std::string::iterator i = s.begin; i != s.end(); i++)
...并表现得好像这是一项重大成就。我不认为它是。对于这样的情况,用迭代器替换整数类型可能几乎没有(如果有的话)收益。同样,采用您发布并更改char const *
为的代码std::string::iterator
似乎不太可能完成很多(如果有的话)。事实上,这样的转换往往使代码更冗长,更难理解,而没有得到任何回报。
如果您要更改代码,您应该(在我看来)这样做是为了通过使其真正通用(std::string::iterator
实际上不会这样做)来使其更加通用。
例如,考虑您的split
(从您链接的帖子中复制):
vector<string> split(const char* start, const char* finish){
const char delimiters[] = ",(";
const char* it;
vector<string> result;
do{
for (it = find_first_of(start, finish, begin(delimiters), end(delimiters));
it != finish && *it == '(';
it = find_first_of(extractParenthesis(it, finish) + 1, finish, begin(delimiters), end(delimiters)));
auto&& temp = interpolate(start, it);
result.insert(result.end(), temp.begin(), temp.end());
start = ++it;
} while (it <= finish);
return result;
}
就目前而言,这仅限于在窄弦上使用。如果有人想使用宽字符串、UTF-32 字符串等,那么要做到这一点相对困难。同样,如果有人想要匹配[
或 '{' 而不是(
,则也需要为此重写代码。
如果有机会支持各种字符串类型,我们可能希望使代码更通用,如下所示:
template <class InIt, class OutIt, class charT>
void split(InIt start, InIt finish, charT paren, charT comma, OutIt result) {
typedef std::iterator_traits<OutIt>::value_type o_t;
charT delimiters[] = { comma, paren };
InIt it;
do{
for (it = find_first_of(start, finish, begin(delimiters), end(delimiters));
it != finish && *it == paren;
it = find_first_of(extractParenthesis(it, finish) + 1, finish, begin(delimiters), end(delimiters)));
auto&& temp = interpolate(start, it);
*result++ = o_t{temp.begin(), temp.end()};
start = ++it;
} while (it != finish);
}
这尚未经过测试(甚至未编译),因此它实际上只是您可以采用代码的一般方向的草图,而不是实际的完成代码。尽管如此,我认为总体思路至少应该是显而易见的——我们不只是将其更改为“使用迭代器”。我们将其更改为泛型,迭代器(作为模板参数传递,此处未直接指定类型)只是其中的一部分。为了走得更远,我们还消除了对括号和逗号字符进行硬编码。虽然不是绝对必要的,但我也更改了参数以更符合标准算法使用的约定,因此(例如)输出也通过迭代器写入,而不是作为集合返回。
虽然它可能不会立即显现出来,但后者确实增加了相当多的灵活性。举个例子,如果有人只是想在拆分字符串后打印出来,他可以传递一个std::ostream_iterator
, 让每个结果在生成时直接写入std::cout
,而不是获取字符串向量,然后必须单独打印出来。