C ++ Вывод через copy () - PullRequest
0 голосов
/ 14 мая 2018

Я играю с C ++ и STL, и я попытался скопировать деку в список и распечатать список с помощью copy () и ostream_iterator. По какой-то причине содержимое списка, в который я скопировал, не печатается, пока я не получу доступ к элементам через front (), back () или at (). Почему первые две попытки печати терпят неудачу:

#include <iostream>
#include <fstream>
#include  <deque>
#include <algorithm>
#include <iterator>
#include <list>
using namespace std;

void alterParticle(string&);

int main(){

   string tmp_str;
   deque<string> d;
   list<string> l;

   ifstream in("foo.txt");
   if(!in.is_open()){
      cout << "Error opening file" << endl;
      return 1;
   }
   while(in){
      getline(in,tmp_str);
      d.push_back(tmp_str);
   }

   for_each(d.begin(),d.end(),alterParticle);

   copy(d.begin(),d.end(),ostream_iterator<string>(cout,"\n"));

   ostream_iterator<string> out(cout,"\n");
   copy_if(d.begin(),d.end(),out,
         [](const string& s){
            if(s.find("fooparticle")!= string::npos)
               return true;
            return false;
         });

   copy_if(d.begin(),d.end(),l.begin(),
      [](const string& s){
         if(s.find("fooparticle")!= string::npos)
            return true;
         return false;
      });

   cout << "First try: " << endl;
   for(string s : l)
      cout << s << endl;

   cout << "Second try: " << endl;
   copy(l.begin(),l.end(),out);

   cout << "Last try: " << l.front() << endl;

   return 0;
}

void alterParticle(string& s){
   int fpos = s.find("quark");
   string rep_str{"quark"};
   if(fpos != string::npos){
      s.replace(s.find(rep_str),rep_str.length(),"fooparticle");
   }
}

Выход:

fooparticle 10 11.4
neutrino 7 20.5
electron 5 6.7
proton 8 9.5

fooparticle 10 11.4
First try:
Second try:
Last try: fooparticle 10 11.4

Edit:

Просто, чтобы было проще понять, почему это не сработало для тех, кто задает тот же вопрос, вот семантика copy_if (). Это довольно ясно показывает, что он не расширяет контейнер:

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

1 Ответ

0 голосов
/ 14 мая 2018

copy и copy_if не добавляют новые элементы в list, они предполагают, что существуют существующие элементы для копирования.Ваш список изначально пуст, и поэтому вы пишете в begin() == end() итератор списка.Это не увеличивает размер списка (именно поэтому первые две попытки ничего не печатают), но если вы обращаетесь к (на самом деле не существующему) первому члену списка, вы можете получить результат, который был там написан.

Нет необходимостискажем, присвоение итератору end() - неопределенное поведение.

Вы можете продолжать использовать copy и друзей, если используете insert_iterator (вы обычно используете back_inserter), аналогично ostream_iterator, который вы уже используете.

...