Путями станд.:: stringstream может установить сбой / плохой бит?

Общая часть кода, который я использую для разделения простой строки, похожа на это:

inline std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

Кто-то упомянул, что это будет тихо "глотать" ошибки, происходящие в std::getline. И конечно я соглашаюсь, что это имеет место. Но мне, пришло в голову, что могло возможно пойти не так, как надо здесь на практике, что я должен буду волноваться о. в основном все это сводится к этому:

inline std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }

    if(/* what error can I catch here? */) {
        // *** How did we get here!? ***
    }

    return elems;
}

A stringstream поддерживается a string, таким образом, мы не должны волноваться ни об одной из проблем, связанных с чтением из файла. Нет никакого преобразования типов, продолжающегося здесь с тех пор getline просто чтения, пока это не видит разделитель строки или EOF. Таким образом, мы не можем получить ни одну из ошибок что что-то как boost::lexical_cast должен волноваться о.

Я просто не могу думать о чем-то помимо отказа выделить достаточно памяти, которая могла пойти не так, как надо, но это просто бросит a std::bad_alloc задолго до std::getline даже происходит. Что я пропускаю?

9
задан Evan Teran 26 June 2011 в 03:17
поделиться

1 ответ

Я не могу представить, какие ошибки, по мнению этого человека, могут произойти, и вам следует попросить их объяснить. Ничего не может пойти не так, кроме ошибок распределения, как вы упомянули, которые возникают, а не проглатываются.

Единственное, что, как я вижу, вы прямо упускаете, - это то, что ss.fail () гарантированно будет истинным после цикла while, потому что это условие проверяется. ( bool (stream) эквивалентно ! Stream.fail () , not stream.good () .) Как и ожидалось, ss.eof () также будет истинным, указывая на то, что сбой произошел из-за EOF.

Однако может возникнуть некоторая путаница в том, что на самом деле происходит. Поскольку getline использует разделитель - завершенные поля, а не разделитель - разделенные поля , входные данные, такие как ] "a \ nb \ n" имеет два вместо трех полей, и это может быть удивительно. Для строк это имеет смысл (и является стандартом POSIX), но сколько полей с разделителем of '-' , вы ожидаете найти в "ab- " после разделения?


Между прочим, вот как я бы написал split :

template<class OutIter>
OutIter split(std::string const& s, char delim, OutIter dest) {
  std::string::size_type begin = 0, end;
  while ((end = s.find(delim, begin)) != s.npos) {
    *dest++ = s.substr(begin, end - begin);
    begin = end + 1;
  }
  *dest++ = s.substr(begin);
  return dest;
}

Это, в первую очередь, позволяет избежать всех проблем с iostreams, избежать дополнительных копий ( строка поддержки stringstream; плюс temp, возвращаемый substr, может даже использовать ссылку C ++ 0x rvalue для семантики перемещения, если поддерживается, как написано), имеет поведение, которое я ожидаю от split (отличное от вашего), и работает с любым контейнером.

deque<string> c;
split("a-b-", '-', back_inserter(c));
// c == {"a", "b", ""}
6
ответ дан 4 December 2019 в 23:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: