используя итераторы ifstream, ofstream так, как это должно быть сделано - PullRequest
3 голосов
/ 19 марта 2011

У меня есть текстовый файл, содержащий несколько слов, по одному в строке.Мне нужно прочитать этот файл и поместить каждое слово в список, тогда пользователь сможет изменить этот список после завершения редактирования, программа запишет измененный список в новый файл.

Так как это объект, ориентированный на c ++У меня будет два класса, один для чтения / записи в файл, а другой для редактирования / связывания со списком и пользователем.

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

bool FileMgr::readToList(list<string> &l)
{
if(!input.is_open())
    return false;

string line;
while(!input.eof())
{
    getline(input, line);
    l.push_back(line);
}
return true;
}

имейте в виду: ввод открывается в конструкторе.вопросы: есть ли менее излишний способ получить эту чертову строку из istream и вернуть ее обратно в l?(без «строки» между).кроме вопросов, эта функция, кажется, работает правильно.

теперь функция вывода:

 bool FileMgr::writeFromList(list<string>::iterator begin, list<string>::iterator end)
{
    ofstream output;
    output.open("output.txt");
    while(begin != end)
    {
        output << *begin << "\n";
        begin++;
    }
    output.close();
    return true;
}

это часть моей основной:

    FileMgr file;
list<string> words;
file.readToList(words);
cout << words.front() << words.back();
list<string>::iterator begin = words.begin();
list<string>::iterator end = words.end();
file.writeFromList(begin, end);

спасибо запомогите, обе функции теперь работают.Что касается стиля, это хороший способ реализовать эти две функции?также часть getline (input, line), которая мне действительно не нравится, у кого-нибудь есть идея получше?

Ответы [ 2 ]

6 голосов
/ 19 марта 2011

Как написано, ваш цикл ввода неверен. Флаг eof устанавливается после операции чтения, которая достигает eof, поэтому вы можете закончить цикл один раз слишком много раз. Кроме того, вы не можете проверить флаги bad и fail. Для получения дополнительной информации о флагах, их значении и о том, как правильно написать цикл ввода, см. Вопрос с часто задаваемыми вопросами о переполнении стека C ++ Семантика флагов на basic_ios.

Ваш цикл в readToList должен выглядеть следующим образом:

std::string line;
while (std::getline(input, line))
{
    l.push_back(line);
}

Чтобы узнать, как это сделать на C ++, см. Ответ Джерри Коффина на Как перебирать cin построчно в C ++? Его первое решение довольно простое и должно дать вам хорошая идея о том, как это выглядит в идиоматическом стиле C ++ в стиле STL.

Для вашей функции writeFromList, как объясняет Томалак, вам нужно взять два итератора. При использовании итераторов в C ++ вы почти всегда должны использовать их попарно: один указывает на начало диапазона, а другой - на конец диапазона. Часто также предпочтительно использовать параметр шаблона для типа итератора, чтобы можно было передавать различные типы итераторов в функцию; это позволяет вам менять местами контейнеры по мере необходимости.

Вам не нужно явно вызывать output.close(): он вызывается автоматически деструктором std::ofstream.

Вы можете использовать std::copy с std::ostream_iterator, чтобы превратить выходной контур в одну строку:

template <typename ForwardIterator>
bool FileMgr::writeFromList(ForwardIterator first, ForwardIterator last)
{
    std::ofstream output("output.txt");

    std::copy(first, last, std::ostream_iterator<std::string>(output, ""));
}
2 голосов
/ 19 марта 2011

writeFromList должны принимать начальный итератор и конечный итератор.Этот подход, основанный на диапазоне, предназначен для итераторов, и именно так их использует stdlib.

Итак:

bool FileMgr::writeFromList(list<string>::iterator it, list<string>::iterator end)
{
    ofstream output("output.txt");

    for (; it != end; ++it)
        output << *it;

    return true;
}

и

file.writeFromList(words.begin(), words.end());

You 'Заметьте, я также немного улучшил использование вашего потока.

В идеале writeFromList будет общим и будет принимать любой тип итератора.Но это будущая работа.

Также обратите внимание, что ваш .eof неправильный .Сделайте это:

string line;
while (getline(input, line))
    l.push_back(line);
...