Способы std::stringstream могут установить бит сбоя/плохого бита?

StackOverflow https://stackoverflow.com/questions/2562906

  •  23-09-2019
  •  | 
  •  

Вопрос

Типичный фрагмент кода, который я использую для простого разделения строк, выглядит следующим образом:

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;
}

А stringstream поддерживается string, поэтому нам не нужно беспокоиться о каких-либо проблемах, связанных с чтением из файла.Здесь не происходит преобразования типов, поскольку getline просто читает, пока не увидит разделитель строки или EOF.Поэтому мы не можем получить ни одной ошибки, например boost::lexical_cast должен беспокоиться.

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

Это было полезно?

Решение

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

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

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


Кстати, вот как бы я писать расколоть:

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, может даже использовать ссылку rvalue C++0x для семантики перемещения, если она поддерживается, как написано), имеет поведение, которое я ожидаю от разделения (отличается от вашего), и работает с любым контейнером.

deque<string> c;
split("a-b-", '-', back_inserter(c));
// c == {"a", "b", ""}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top