манипуляторы — демонстрация noskipws в стек переполнения

Я пробовал манипулятор noskipws в C ++ и написал следующий код.

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
string first, middle, last;

istringstream("G B Shaw") >> first >> middle >> last;
cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
istringstream("G B Shaw") >> noskipws >> first >> middle >> last;
cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
}

Я ожидаю следующий вывод:

Ожидаемый результат

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = B

Выход

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = Shaw

Я изменил этот код, чтобы он работал для таких символов, как этот, и он прекрасно работает.

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
char first, middle, last;

istringstream("G B S") >> first >> middle >> last;
cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
istringstream("G B S") >> noskipws >> first >> middle >> last;
cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
}

Я знаю, как работает CIN, и я не смог понять, почему он работает таким образом в случае string,

0

Решение

std::istringstream("G B S") >> std::noskipws >> first >> middle >> last;

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

21.4.8.9 Вставки и экстракторы

 template<class charT, class traits, class Allocator>
basic_istream<charT, traits>&
operator>>(basic_istream<charT, traits>& is,
basic_string<charT, traits, Allocator>& str);

Эффекты: ведет себя как отформатированная функция ввода (27.7.2.2.1). После постройки часового объекта, если часовой переходит в true, звонки str.erase() а затем извлекает символы из is и добавляет их к str как будто позвонив str.append(1, c). […]

Первое чтение извлечет строку "G" в first, Для второго извлечения ничего не будет извлечено, потому что std::noskipws установлен флаг формата, отключающий очистку начальных пробелов. Из-за этого строка очищается, а затем извлечение завершается неудачно, потому что не было введено никаких символов. Вот продолжение вышеприведенного предложения:

21.4.8.9 Устройства для вставки и извлечения (продолжение)

[…] Символы извлекаются и добавляются, пока не произойдет одно из следующих действий:

  • n символы хранятся;

  • конец файла встречается во входной последовательности;

  • isspace(c, is.getloc()) верно для следующего доступного ввода
    персонаж c,

Когда поток определяет неудачное извлечение, std::ios_base::failbit устанавливается в состояние потока, указывающее на ошибку.

С этого момента любая попытка ввода-вывода потерпит неудачу, если состояние потока не будет очищено. Экстрактор становится неработоспособным и не будет работать, если состояние потока не очищено от всех его ошибок. Это означает, что извлечение в last ничего не делает и сохраняет значение, которое имело при предыдущем извлечении std::noskipws) потому что поток не очистить строку.


Что касается причины, почему с помощью char работает: символы не имеют требований к форматированию в C или C ++. Любой и все символы могут быть извлечены в объект типа char, что является причиной того, почему вы видите правильный вывод, несмотря на std::noskipws устанавливается:

27.7.2.2.3 / 1 [istream :: extractors]

template<class charT, class traits>
basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& in,
charT& c);

Эффекты: ведет себя как отформатированный входной элемент (как описано в 27.7.2.2.1) из in. После того, как часовой объект создан, символ извлекается из in, если таковой имеется и хранится в c, В противном случае вызовы функции in.setstate(failbit),

Семантика для экстрактора сохранит символ в его операнде если таковой имеется. Он не ограничивает пробел (или даже символ EOF!). Он будет извлекать его как обычный персонаж.

4

Другие решения

Основной алгоритм для >> строки это:

1) пропустить пробелы
2) читать и извлекать до следующего пробела

Если вы используете noskipwsтогда first step is skipped,

После первого чтения вы позиционируете себя на пустом месте, поэтому следующее (и все последующее) чтение немедленно остановится, ничего не извлекая.
Для получения дополнительной информации вы можете увидеть этот.

форма cplusplus.com ,

многие операции извлечения рассматривают сами пробелы как завершающий символ, поэтому при отключенном флаге skipws некоторые операции извлечения могут вообще не извлекать символы из потока.
Итак, удалите noskipws при использовании со строками.

1

Причина в том, что во втором примере вы вообще не читаете последнюю переменную, а вместо этого вы печатаете ее старое значение.

std::string first, middle, last;
std::istringstream iss("G B S");
^^^
iss >> first >> middle >> last;
std::cout << "Default behavior: First Name = " << first
<< ", Middle Name = " << middle << ", Last Name = " << last << '\n';
std::istringstream iss2("G B T");
^^^
iss2 >> std::noskipws >> first >> middle >> last;
std::cout << "noskipws behavior: First Name = " << first
<< ", Middle Name = " << middle << ", Last Name = " << last << '\n';

Поведение по умолчанию: Имя = G, Отчество = B, Фамилия = S

Поведение noskipws: Имя = G, Отчество =, Фамилия = S

Это происходит потому, что после второго чтения переменной последний поток помещается в пробел.

0
По вопросам рекламы [email protected]