Итераторы предназначены для обеспечения абстракции над указателями.
Например, увеличение итератора всегда манипулирует итератором так, что если в коллекции есть следующий элемент, он ссылается на этот следующий элемент. Если он уже ссылался на последний элемент в коллекции, после приращения это будет уникальное значение, которое не может быть разыменовано, но будет сравниваться с равным другому итератору, указывающему один за концом той же коллекции (обычно получается с помощью collection.end()
).
В конкретном случае итератора в строку (или вектор) указатель предоставляет все возможности, необходимые для итератора, поэтому указатель можно использовать в качестве итератора без потери требуемой функциональности.
Например, вы можете использовать std::sort
для сортировки элементов в строке или векторе. Поскольку указатели предоставляют необходимые возможности, вы также можете использовать их для сортировки элементов в собственном массиве (в стиле C).
В то же время да, определение (или использование) итератора, отдельного от указателя, может предоставить дополнительные возможности, которые не являются строго обязательными. Просто, например, некоторые итераторы обеспечивают по крайней мере некоторую степень проверки, чтобы гарантировать, что (например) при сравнении двух итераторов они оба являются итераторами в одной и той же коллекции, и что вы не пытаетесь получить доступ за пределы. Необработанный указатель не может (или, по крайней мере, обычно не будет) предоставлять такую возможность.
Многое из этого восходит к менталитету «не плати за то, чем не пользуешься». Если вам действительно нужны и нужны только возможности нативных указателей, их можно использовать в качестве итераторов, и вы обычно получаете код, практически идентичный коду, полученному при прямом манипулировании указателями. В то же время, в тех случаях, когда вам нужны дополнительные возможности, такие как обход многопоточного дерева RB или дерева 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
по мере его создания, вместо того, чтобы получать вектор строк, а затем печатать их отдельно. из.
person
Jerry Coffin
schedule
17.03.2015