Как работает алгоритм copy () из Exception C ++, глава 1, часть 1?

0

Трава представляет способ циклы через вектор:

for(vector<int>::iterator i = v.begin(); i < v.end(); i++) {
 cout << *i << endl;
}

Он заменяет этот код:

copy(v.begin(), v.end(), ostream_iterator<int>(cout, "\n"));

Я изо всех сил пытаюсь понять, как, или почему это работает. Я просмотрел функцию копирования, и в документации говорится, что она эквивалентна:

template<class InputIterator, class OutputIterator>
  OutputIterator copy (InputIterator first, InputIterator last, 
                       OutputIterator result)
{
  while (first!=last) {
    *result = *first;
    ++result; ++first;
  }
  return result;
}

Поэтому я задал вопрос: "Что происходит, когда мы * OutputIterator?"

reference operator*() const;

Dereference iterator
Returns *this.

И тут я смутился. Я не вижу определения того, что указывает OutputIterator. Кроме того, я не вижу, как строка *result = *first; возможно, перевести на вызов cout << *i;

  • 2
    Посмотрите на ostream_iterator. Его оператор = () делает магию.
  • 0
    Кстати, это хороший пример того, как работать с алгоритмами, но в C ++ 11 for (const auto& obj: myObjVector) { std::cout << obj << std::endl; } предпочтительнее из-за своей простоты.
Теги:
vector
copy
stl

1 ответ

5
Лучший ответ

Вы только посмотрели, что делает OutputIterator. OutputIterator - это всего лишь набор требований, с которыми OutputIterator множество типов в стандартной библиотеке. Одним из таких типов является std::ostream_iterator, поэтому вам нужно посмотреть, как это происходит в контексте std::copy.

Поэтому в алгоритме копирования мы *result = *first делаем *result = *first. Во-первых, operator* для std::ostream_iterator ничего не делает - он просто возвращает сам итератор. Магия происходит, когда мы назначаем этот итератор. Если вы посмотрите на std::ostream_iterator::operator=, вы увидите, что назначение этого итератора будет вставляться (используя <<) в поток, с которым он был построен. Таким образом, назначение в вашем случае будет передано в std::cout.

После этого оба result и first увеличиваются. Приращение result (std::ostream_iterator) не влияет, и приращение first переместится к следующему элементу вектора. Затем в следующей итерации этот следующий элемент снова вставлен в std::cout и т.д.

Как вы можете видеть, std::ostream_iterator действительно не ведет себя так, как вы ожидали, что типичный итератор будет вести себя (перемещение по последовательности элементов, где выполнение косвенности на них дает вам текущий элемент). Однако он удовлетворяет требованиям OutputIterator и поэтому может использоваться как один.


Здесь выполняется реализация std::ostream_iterator::operator= из libstdc++:

/// Writes @a value to underlying ostream using operator<<.  If
/// constructed with delimiter string, writes delimiter to ostream.
ostream_iterator&
operator=(const _Tp& __value)
{
  __glibcxx_requires_cond(_M_stream != 0,
                          _M_message(__gnu_debug::__msg_output_ostream)
                          ._M_iterator(*this));
  *_M_stream << __value;
  if (_M_string) *_M_stream << _M_string;
  return *this;
}

Игнорируя утверждение в первой строке, мы видим, что он затем вставляет значение __value во внутренний поток _M_stream. Затем, если есть разделитель, _M_string, он также вставлен в _M_stream. Затем он возвращается.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню