Перейти к содержимому

Cin sync c что это

  • автор:

Cin sync c что это

There are two problems with this code. Let’s look at the first problem — what happens when we type in two words?

Enter Text: Hello, World! Enter Number: Enter Another Number: You Entered: Hello,, 

and the rest of the output would be undefined. This is because it only reads in stuff until a space, so the leftover text is there for when it tries cin >> n, which won’t work. To fix it, we can add cin.sync() after the cin >> str, which will synchronize the input stream with whatever has been entered.

The second problem is that this program would end before we saw the output — this can be fixed with cin.get() or cin.ignore(), but if the user typed in two things for Another Number, it would get that and end. To solve this, you can add cin.sync(); cin.ignore();, which will hold the window open until you press enter.

@L B
perfect example, thanx.
i used to use cin.get() but got hit by some strange behavior (i know it s dumb).
will it work the same after a getline(cin,stringname) ?

Класс basic_istream

Описывает объект, который управляет извлечением элементов и закодированными объектами из буфера потока с элементами типа Char_T , также известным как char_type , признаки символов которого определяются классом Tr , также известным как traits_type .

Синтаксис

template > class basic_istream : virtual public basic_ios

Замечания

Большинство функций-членов, которые перегружены operator>> , форматируют входные функции. Они следуют этому шаблону:

iostate state = goodbit; const sentry ok(*this); if (ok) < try < /*extract elements and convert accumulate flags in state. store a successful conversion*/ >catch (. ) < try < setstate(badbit); >catch (. ) < >if ((exceptions()& badbit) != 0) throw; > > setstate(state); return (*this); 

Многие другие функции-члены — это неформатированные входные функции. Они следуют этому шаблону:

iostate state = goodbit; count = 0; // the value returned by gcount const sentry ok(*this, true); if (ok) < try < /* extract elements and deliver count extracted elements in count accumulate flags in state */ >catch (. ) < try < setstate(badbit); >catch (. ) < >if ((exceptions()& badbit) != 0) throw; > > setstate(state); 

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

Объект класса basic_istream хранит:

  • Виртуальный общедоступный базовый объект класса basic_ios . Дополнительные сведения см. в разделе basic_ios .
  • Счетчик извлечения для последней неформатированных входных операций (вызывается count в предыдущем коде).

Пример

Дополнительные сведения о входных потоках см. в примере basic_ifstream класса .

Конструкторы

Конструктор Description
basic_istream Создает объект типа basic_istream .

Функции элементов

Функция-член Description
gcount Возвращает число символов, считанных во время последнего неформатированного ввода.
get Считывает один или несколько символов из входного потока.
getline Считывает строку из входного потока.
ignore Пропускает несколько элементов после текущей позиции чтения.
peek Возвращает следующий символ для чтения.
putback Помещает указанный символ в поток.
read Считывает указанное количество символов из потока и сохраняет их в массиве.
readsome Чтение только из буфера.
seekg Перемещает позицию чтения в потоке.
sentry Вложенный класс описывает объект, объявление которого структурирует форматированные и неформатированные входные функции.
swap Меняет местами этот объект basic_istream с указанным параметром объекта basic_istream .
sync Синхронизирует связанное с потоком устройство ввода с буфером потока.
tellg Сообщает текущую позицию чтения в потоке.
unget Помещает самый последний считанный символ обратно в поток.

Операторы

Operator Description
operator>> Вызывает функцию для входного потока или считывает форматированные данные из входного потока.
operator= Назначает basic_istream справа от оператора этому объекту. Это назначение перемещения, включающее ссылку rvalue , которая не оставляет копию позади.

Требования

Заголовок.

Пространство имен std :

basic_istream::basic_istream

Создает объект типа basic_istream .

explicit basic_istream( basic_streambuf* strbuf, bool _Isstd = false); basic_istream(basic_istream&& right); 

Параметры

_Isstd
true Значение , если это стандартный поток; false в противном случае .

right
Объект basic_istream для копирования.

Замечания

Первый конструктор инициализирует базовый класс путем вызова init(strbuf) . Он также хранит нуль в счетчике извлечений. Дополнительные сведения см. в разделе init . Дополнительные сведения об этом количестве извлечения см. в разделе «Примечания» в обзоре basic_istream класса .

Второй конструктор инициализирует базовый класс путем вызова move(right) . Он также сохраняет в счетчике извлечения и сохраняет right.gcount() ноль в счетчике извлечения для right .

Пример

Дополнительные сведения о входных потоках см. в примере basic_ifstream::basic_ifstream .

basic_istream::gcount

Возвращает число символов, считанных во время последнего неформатированного ввода.

streamsize gcount() const; 

Возвращаемое значение

Замечания

Используется basic_istream::get для чтения неформатированных символов.

Пример

// basic_istream_gcount.cpp // compile with: /EHsc #include using namespace std; int main( )
Type the letter 'a': a 1 

basic_istream::get

Считывает один или несколько символов из входного потока.

int_type get(); basic_istream& get(Char_T& Ch); basic_istream& get(Char_T* str, streamsize count); basic_istream& get(Char_T* str, streamsize count, Char_T delimiter); basic_istream& get(basic_streambuf& strbuf); basic_istream& get(basic_streambuf& strbuf, Char_T delimiter); 

Параметры

count
Число символов для чтения из strbuf .

delimiter
Символ, который должен завершить чтение, если он обнаружен раньше count .

str
Строка, в которую должна выполняться запись.

Ch
Символ для получения.

strbuf
Буфер, в который должна выполняться запись.

Возвращаемое значение

Без параметров форма get возвращает элемент, считываемый как целое число или конец файла. Остальные формы возвращают поток ( *this ).

Замечания

Первая неформатированная входная функция извлекает элемент, если это возможно, как будто возвращается rdbuf->sbumpc . В противном случае возвращается значение traits_type:: eof . Если функция извлекает элемент без элемента, вызывается setstate(failbit) . Дополнительные сведения см. в разделе setstate .

Вторая функция извлекает int_type элемент meta таким же образом. Если meta сравнивается равным traits_type::eof , вызывается setstate(failbit) функция. В противном случае он хранится traits_type::to_char_type(meta) в Ch . Функция возвращает *this . Дополнительные сведения см. в разделе to_char_type .

Третья функция возвращается get(str, count, widen(‘\n’)) .

Четвертая функция извлекает элементы count — 1 и сохраняет их в массиве, начиная с str . Она всегда сохраняет char_type после сохранения всех извлеченных элементов. В целях тестирования извлечение останавливается:

  • в конце файла;
  • После извлечения элемента, который сравнивается с delimiter . В этом случае элемент возвращается к управляемой последовательности.
  • После извлечения count — 1 элементов функции.

Если функция не извлекает ни один элемент, она вызывает setstate(failbit) . В любом случае она возвращает *this .

Возвращается пятая функция get(strbuf, widen(‘\n’)) .

Шестая функция извлекает элементы и вставляет их в strbuf . Извлечение останавливается в конце файла или на элементе, который сравнивается с равным delimiter , который не извлекается. Оно также останавливается без извлечения соответствующего элемента, если вставка завершается неудачно или создает исключение (которое перехватывается, но не создается повторно). Если функция не извлекает ни один элемент, она вызывает setstate(failbit) . В любом случае функция возвращается *this .

Пример

// basic_istream_get.cpp // compile with: /EHsc #include using namespace std; int main( )
1111 

basic_istream::getline

Получает строку из входного потока.

basic_istream& getline( char_type* str, streamsize count); basic_istream& getline( char_type* str, streamsize count, char_type delimiter); 

Параметры

count
Число символов для чтения из strbuf .

delimiter
Символ, который должен завершить чтение, если он обнаружен раньше count .

str
Строка, в которую должна выполняться запись.

Возвращаемое значение

Замечания

Первая из этих неформатированных входных функций возвращается getline(str, count, widen(‘\n’)) .

Вторая функция извлекает элементы count — 1 и сохраняет их в массиве, начиная с str . Она всегда сохраняет символ окончания строки после сохранения всех извлеченных элементов. В целях тестирования извлечение останавливается:

  • в конце файла;
  • После извлечения элемента, который сравнивается с delimiter . В этом случае элемент не помещается обратно, и он не добавляется к управляемой последовательности.
  • После извлечения count — 1 элементов функции.

Если функция извлекает элементы или count — 1 элементы, вызывается setstate(failbit) . В любом случае она возвращает *this . Дополнительные сведения см. в разделе setstate .

Пример

// basic_istream_getline.cpp // compile with: /EHsc #include using namespace std; int main( )

basic_istream::ignore

Пропускает несколько элементов после текущей позиции чтения.

basic_istream& ignore( streamsize count = 1, int_type delimiter = traits_type::eof()); 

Параметры

count
Количество пропускаемых элементов от текущей позиции чтения.

delimiter
Элемент, который, если обнаружен до подсчета, вызывает ignore возврат и разрешение всех элементов после delimiter чтения.

Возвращаемое значение

Замечания

Неформатированная входная функция извлекает до count элементов и удаляет их. Однако если count равно numeric_limits::max , оно принимается как произвольно большое. Извлечение останавливается рано на конце файла или на элементе Ch , который traits_type::to_int_type(Ch) сравнивается с delimiter (который также извлекается). Функция возвращает *this . Дополнительные сведения см. в разделе to_int_type .

Пример

// basic_istream_ignore.cpp // compile with: /EHsc #include int main( ) < using namespace std; char chararray[10]; cout > chararray; cout
Type 'abcdef': abcdef def 

basic\_istream::operator>>

Вызывает функцию для входного потока или считывает форматированные данные из входного потока.

basic_istream& operator>>(basic_istream& (* Pfn)(basic_istream&)); basic_istream& operator>>(ios_base& (* Pfn)(ios_base&)); basic_istream& operator>>(basic_ios& (* Pfn)(basic_ios&)); basic_istream& operator>>(basic_streambuf* strbuf); basic_istream& operator>>(bool& val); basic_istream& operator>>(short& val); basic_istream& operator>>(unsigned short& val); basic_istream& operator>>(int& val); basic_istream& operator>>(unsigned int& val); basic_istream& operator>>(long& val); basic_istream& operator>>(unsigned long& val); basic_istream& operator>>(long long& val); basic_istream& operator>>(unsigned long long& val); basic_istream& operator>>(void *& val); basic_istream& operator>>(float& val); basic_istream& operator>>(double& val); basic_istream& operator>>(long double& val); 

Параметры

Pfn
Указатель функции.

strbuf
Объект типа stream_buf .

val
Значение для чтения из потока.

Возвращаемое значение

Замечания

Заголовок также определяет несколько глобальных операторов извлечения. Дополнительные сведения см. в разделе operator>> (\) .

Первая функция-член гарантирует, что выражение вызовов ws(istr) форм istr >> ws , а затем возвращается *this . Дополнительные сведения см. в разделе ws .

Второй и третий функции обеспечивают аналогичное поведение других манипуляторов, таких как hex . Остальные функции — это отформатированные входные функции.

basic_istream& operator>>( basic_streambuf* strbuf); 

извлекает элементы, если strbuf не является пустым указателем, и вставляет их в strbuf . Извлечение останавливается в конце файла. Оно также останавливается без извлечения соответствующего элемента, если вставка завершается неудачно, или создает исключение (которое перехватывается, но не создается повторно). Если функция не извлекает ни один элемент, она вызывает setstate(failbit) . В любом случае функция возвращается *this . Дополнительные сведения см. в разделе setstate .

basic_istream& operator>>(bool& val); 

извлекает поле и преобразует его в логическое значение путем вызова use_facet< num_get(getloc).get( InIt(rdbuf), Init(0), *this, getloc, val) . InIt Здесь определяется как istreambuf_iterator . Функция возвращает *this .

Дополнительные сведения см. в разделе use_facet , getloc , get , rdbuf и istreambuf_iterator .

Каждая из функций:

basic_istream& operator>>(short& val); basic_istream& operator>>(unsigned short& val); basic_istream& operator>>(int& val); basic_istream& operator>>(unsigned int& val); basic_istream& operator>>(long& val); basic_istream& operator>>(unsigned long& val); basic_istream& operator>>(long long& val); basic_istream& operator>>(unsigned long long& val); basic_istream& operator>>(void *& val); 

извлеките поле и преобразуйте его в числовое значение путем вызова use_facet(getloc).get(InIt(rdbuf), Init(0), *this, getloc, val) . InIt Здесь определяется как val istreambuf_iterator и имеет тип long unsigned long или void * по мере необходимости.

Если преобразованное значение не может быть представлено как тип val , вызывается setstate(failbit) функция. В любом случае функция возвращается *this . Дополнительные сведения см. в разделе setstate .

Каждая из функций:

basic_istream& operator>>(float& val); basic_istream& operator>>(double& val); basic_istream& operator>>(long double& val); 

извлеките поле и преобразуйте его в числовое значение путем вызова use_facet(getloc).get(InIt(rdbuf), Init(0), *this, getloc, val) . InIt Здесь определяется как istreambuf_iterator val и имеет тип double или long double по мере необходимости.

Если преобразованное значение не может быть представлено как тип val , вызывается setstate(failbit) функция. В любом случае она возвращает *this .

Пример

// istream_basic_istream_op_is.cpp // compile with: /EHsc #include using namespace std; ios_base& hex2( ios_base& ib ) < ib.unsetf( ios_base::dec ); ib.setf( ios_base::hex ); return ib; >basic_istream >& somefunc(basic_istream > &i) < if ( i == cin ) < cerr return i; > int main( ) < int i = 0; cin >> somefunc; cin >> i; cout > hex2; cin >> i; cout

basic_istream::operator=

Назначает basic_istream справа от оператора этому объекту. Это назначение перемещения, включающее ссылку rvalue , которая не оставляет копию позади.

basic_istream& operator=(basic_istream&& right); 

Параметры

right
Ссылка rvalue на объект basic_ifstream .

Возвращаемое значение

Замечания

Оператор-член вызывает swap(right) .

basic_istream::peek

Возвращает следующий символ для чтения.

int_type peek(); 

Возвращаемое значение

Следующий символ для чтения.

Замечания

Неформатированная входная функция извлекает элемент, если это возможно, как будто возвращается rdbuf->sgetc . В противном случае возвращается значение traits_type::eof . Дополнительные сведения см. в разделах sgetc и eof .

Пример

// basic_istream_peek.cpp // compile with: /EHsc #include using namespace std; int main( )
abcde 
Type 'abcde': abcde a abcde 

basic_istream::putback

Помещает указанный символ в поток.

basic_istream& putback( char_type Ch); 

Параметры

Ch
Символ для помещения обратно в поток.

Возвращаемое значение

Замечания

Неформатированные входные функции возвращаются Ch , если это возможно, как при вызове rdbuf->sputbackc . Если rdbuf имеет значение NULL, или если вызов sputbackc возвращается traits_type::eof , функция вызывается setstate(badbit) . В любом случае она возвращает *this .

Дополнительные сведения см. в разделе rdbuf , sputbackc , eof , и setstate .

Пример

// basic_istream_putback.cpp // compile with: /EHsc #include using namespace std; int main( )

basic_istream::read

Считывает указанное количество символов из потока и сохраняет их в массиве.

Этот метод является потенциально опасным, так как зависит от вызывающего объекта при проверке правильности переданных значений.

basic_istream& read( char_type* str, streamsize count); 

Параметры

str
Массив, из которого должны считываться символы.

count
Число символов для чтения.

Возвращаемое значение

Поток ( *this ).

Замечания

Неформатированная входная функция извлекает элементы count и сохраняет их в массиве, начиная с str . Извлечение останавливается рано в конце файла, в этом случае вызовы setstate(failbit) функции. В любом случае она возвращает *this . Дополнительные сведения см. в разделе setstate .

Пример

// basic_istream_read.cpp // compile with: /EHsc #include using namespace std; int main() < char c[10]; int count = 5; cout 
abcde 
Type 'abcde': abcde abcde 

basic_istream::readsome

Считывает указанное число значений символов.

Этот метод является потенциально опасным, так как зависит от вызывающего объекта при проверке правильности переданных значений.

streamsize readsome( char_type* str, streamsize count); 

Параметры

str
Массив, в котором readsome сохраняет символы, которые считывает.

count
Число символов для чтения.

Возвращаемое значение

Количество символов, которые фактически считываются, gcount .

Замечания

Эта неформатированная входная функция извлекает до count элементов и сохраняет их в массив str .

Эта функция не ожидает входных данных. Она считывает все доступные данные.

Пример

// basic_istream_readsome.cpp // compile with: /EHsc /W3 #include using namespace std; int main( ) < char c[10]; int count = 5; cout 

basic_istream::seekg

Перемещает позицию чтения в потоке.

basic_istream& seekg(pos_type pos); basic_istream& seekg(off_type off, ios_base::seekdir way); 

Параметры

pos
Абсолютное положение, в которое следует переместить указатель чтения.

off
Смещение для перемещения указателя чтения относительно way .

Возвращаемое значение

Замечания

Первая функция-член выполняет как абсолютный поиск, вторая функция-член выполняет относительный поиск.

Не используйте вторую функцию-член с текстовыми файлами, так как стандартный C++ не поддерживает относительный поиск в текстовых файлах.

Если fail это false , первый вызов newpos = rdbuf->pubseekpos(pos) функции-член для некоторых временных pos_type объектов newpos . В противном случае fail false второй вызов newpos = rdbuf->pubseekoff( off, way) функции. В любом случае, если (off_type)newpos == (off_type)(-1) (операция размещения завершается ошибкой), вызов функции istr.setstate(failbit) . Обе функции возвращают значение *this .

Если fail есть true , функции-члены ничего не делают.

Дополнительные сведения см. в разделе rdbuf , pubseekpos , pubseekoff , и setstate .

Пример

// basic_istream_seekg.cpp // compile with: /EHsc #include #include int main ( ) < using namespace std; ifstream file; char c, c1; file.open( "basic_istream_seekg.txt" ); file.seekg(2); // seek to position 2 file >> c; cout

basic_istream::sentry

Вложенный класс описывает объект, объявление которого структурирует форматированные и неформатированные входные функции.

class sentry < public: explicit sentry( basic_istream& _Istr, bool _Noskip = false); operator bool() const; >; 

Замечания

В противном случае _Istr.good true конструктор:

  • Вызовы _Istr.tie->flush , если _Istr.tie не является пустым указателем.
  • Фактически вызывается ws(_Istr) , если _Istr.flags & skipws ненулевое значение.

Если после какой-либо такой подготовки, _Istr.good false конструктор вызывает _Istr.setstate(failbit) . В любом случае конструктор сохраняет значение, возвращаемое _Istr.good в status . Последующий вызов для operator bool доставки этого сохраненного значения.

Дополнительные сведения см. в разделе good , , ws tie flush , , flags , skipws и setstate .

basic_istream::swap

Меняет местами содержимое двух объектов basic_istream .

void swap(basic_istream& right); 

Параметры

right
Ссылка lvalue на объект basic_istream .

Замечания

Вызовы basic_ios::swap(right) функции-члены. Она также обменивает количество извлечения с соответствующим значением для right . Дополнительные сведения см. в разделе basic_ios::swap .

basic_istream::sync

Синхронизирует связанное с потоком устройство ввода с буфером потока.

int sync(); 

Возвращаемое значение

Если rdbuf имеет значение NULL, функция возвращает значение -1. В противном случае вызывается rdbuf->pubsync . Если этот вызов возвращает -1, функция вызывает setstate(badbit) и возвращает -1. В противном случае функция возвращает нуль. Дополнительные сведения см. в разделах pubsync и setstate .

basic_istream::tellg

Сообщает текущую позицию чтения в потоке.

pos_type tellg(); 

Возвращаемое значение

Текущая позиция в потоке.

Замечания

Если fail есть false , функция-член возвращается rdbuf->pubseekoff(0, cur, in) . В противном случае возвращается значение pos_type(-1) . Дополнительные сведения см. в разделах rdbuf и pubseekoff .

Пример

// basic_istream_tellg.cpp // compile with: /EHsc #include #include int main() < using namespace std; ifstream file; char c; streamoff i; file.open("basic_istream_tellg.txt"); i = file.tellg(); file >> c; cout > c; cout

basic_istream::unget

Помещает самый последний считанный символ обратно в поток.

basic_istream& unget(); 

Возвращаемое значение

Замечания

Неформатированная входная функция возвращает предыдущий элемент в потоке, если это возможно, как если бы вызывая rdbuf->sungetc rdbuf , если это пустой указатель, или если вызов sungetc возвращался traits_type::eof , функция вызывает setstate(badbit) . В любом случае она возвращает *this .

Дополнительные сведения см. в статьях sungetc , eof и setstate . Сведения о том, как unget может завершиться сбоем, см. в статье basic_streambuf::sungetc .

Пример

// basic_istream_unget.cpp // compile with: /EHsc #include using namespace std; int main( )
Type 'abc': abc abc 

Проверка вводимых потоковых данных С++

Если данные вводятся в формы – то правильный путь – использование валидаторов. Если данные считываются с файла в JSON/XML форматах используйте JSON-схему или XSD/DTD. Ну а эта инструкция посвящена работе с потоками типа cin, ifstream.

Валидация ввода чисел

Итак, мы считали целое число с консоли:

int a; cin >> a;

Что если пользователь ввел не целое число или строку? При этом поднимется флаг ошибки потока cin. Не вдаваясь в подробности, проверить его можно функцией cin.fail() . Но нам надо не просто проверить, а попросить пользователя ввести данные еще раз. Перед следующей попыткой ввода надо снять флаг ошибки функцией cin.clear() и удалить все находящиеся в нем данные. Для удаления данных можно использовать такую конструкцию: cin.ignore(cin.rdbuf()->in_avail()); или такую: cin.sync(); тут функция rdbuf возвращет буфер, а in_avail – количество байт в нем. Однако, это работает не всегда (не во всех компиляторах), in_avail часто возвращает некорректные значения. Вместо этого можно передать в ignore любое большое число, задающее число байт, которые надо пропустить. Удобен и переносим такой вариант: std::cin.ignore(std::numeric_limits::max(), '\n'); Итого, чтобы считать целое число используем такую конструкцию:

int a; cin >> a; while (cin.fail())< cin.clear(); std::cin.ignore(std::numeric_limits::max(), '\n'); cout > a; >

Валидация ввода строки

Допустим, мы думаем, что в файле находится строка не более чем из N символов. Считаем ее так:

char s1[N]; cin.getline(s1, N,'\n');

Что может пойти не так? – На самом деле, мы считываем строку не более чем из N символов или до символа перевода строки. Если перед этим мы считали с клавиатуры число (например как описано выше) – то в буфере остается символ перевода строки, так как оператор >> не удаляет его из потока. Часто для этого выполняют что-то типа cin.get() , однако более надежно вызвать что-то типа std::cin.ignore(std::numeric_limits::max(), '\n'); Ну а что если пользователь ввел строку из более чем N символов? Проблема в том, что сама собой она не обрежется, а самое главное – в этом случае поднимется флаг ошибки ( cin.fail ) и любое последующее обращение к потоку сломает вашу программу. итак, мы пришли к такому варианту:

char s1[N]; std::cin.ignore(std::numeric_limits::max(), '\n'); cin.getline(s1, N,'\n'); if (cin.fail()) < cin.clear(); std::cin.ignore(std::numeric_limits::max(), '\n'); >

Этот вариант считывает с потока строку (не более чем из N символов), а остальные – игнорирует (до символа перевода строки). Однако, если вы хотите при некорректном ввода попросить пользователя ввести данные повторно, используйте такой вариант:

char s1[N]; std::cin.ignore(std::numeric_limits::max(), '\n'); cin.getline(s1, N,'\n'); while (cin.fail()) < cin.clear(); std::cin.ignore(std::numeric_limits::max(), '\n'); cout

Cin sync c что это

CheaterExposer → [UPDATE] Codeforces Cheater IOI Medalist

maomao90 → I am top 1 contributor. AMA!

bycicle → Click here if you want a fast way to get rid of your alt

MikeMirzayanov → Codeforces Single Account Policy: zh0ukangyang is Removed from the Rating

maomao90 → Editorial for Hello 2024

standoff → Еhis isn't fair.

sarthak1357 → CSES shortest routes 1

mohammed_orkhan → I wnat to be EXPERT!!

Некропост

Pyqe → Codeforces Round #831 (Div. 1 + Div. 2, based on COMPFEST 14 Final) Editorial

Некропост

arham_doshi → cses graph session editorial(incomplete)

SAD_IN_NIGHTMARE → 2024 OIs

parth_1818 → Know Some Sorting Techniques

stefdasca → Easy and Quick Video Tutorials for the CSES Problem Set

I_am_Polish_Girl → Dijkstra Algorithgm

atcoder_official → AtCoder Beginner Contest 335 (Sponsored by Mynavi) Announcement

awoo → Разбор Educational Codeforces Round 149

Vectrizz → Золотой расчет: оптимизация ценности в рюкзаке с умением раздробить слитки!

Hexagons → [OFF TOPIC] Hollow Knight radiant tutorial for bossfight "Markoth"

pajenegod → The Ultimate Reroot Template

triumphh → What rating on codeforces should I aim for to crack ZCO and INOI?

Некропост

sahal → CSES Problemset Editorials (almost all section editorial collection)

Некропост

Zlobober → Checkers with testlib.h

oversolver → Expert for the first time since 2011, AMA

Algorithms_with_Shayan → How to approach DP problems & DP playlist

Nurali16 → tourist is not noob . he is genius

Блог пользователя andreyv

Снова про ввод/вывод в C++

Автор andreyv, 11 лет назад ,

Хочу продолжить тему скорости ввода/вывода в C++, которую когда-то начал товарищ freopen. freopen сравнивал производительность двух способов ввода/вывода в C++: унаследованной от C библиотеки stdio ( ) и более новой библиотеки iostreams ( /…). Однако в этих тестах не было учтено, что iostreams можно значительно ускорить, включив некоторые оптимизации. Об их существовании уже неоднократно упоминалось на Codeforces (раз, два, три). Сейчас я написал софт, который сравнивает производительность stdio и iostreams на стандартном вводе/выводе с учётом этого.

UPD1: Добавлена информация про _CRT_DISABLE_PERFCRIT_LOCKS .
UPD2: Для полноты картины добавлены вызовы printf() / scanf() на строках.

Что это за оптимизации?

Первая состоит в том, что в начале программы, перед каким-либо вводом/выводом, можно вставить строчку

ios_base::sync_with_stdio(false);

Эта команда отключает синхронизацию iostreams с stdio (описание). По умолчанию она включена, то есть, iostreams и stdio можно использовать вместе на одном и том же потоке, перемежая их вызовы. После отключения синхронизации так делать больше нельзя, однако за счёт этого iostreams может работать быстрее.

Вторая оптимизация заключается в том, что для cin можно выключить привязку к cout :

cin.tie(NULL);

По умолчанию cin привязан к cout , что означает, что перед каждой операцией над cin сначала сбрасывается буфер cout (описание). Отключение этой функции опять-таки позволяет iostreams работать быстрее. С этой оптимизацией надо быть внимательным в интерактивных задачах: либо не использовать её, либо не забывать явный flush .

Отмечу ещё, что на производительность iostreams негативно влияет частое использование endl , поскольку endl не только выводит символ новой строки, но и сбрасывает буфер потока (описание). Вместо endl можно просто выводить '\n' или "\n" .

Какие тесты включены в программу?

Я постарался сымитировать наиболее типичные ситуации, возникающие при решении задач.

  • Ввод/вывод int с помощью stdio, iostreams и, для сравнения, самопальных функций
  • Ввод/вывод double
  • Посимвольный ввод/вывод
  • Ввод/вывод строк: как с char * , так и с std::string

Какие тесты не включены в программу?

  • long long — полагаю, результат будет коррелировать с int
  • Преобразование int и запись результата в собственный буфер достаточно большого размера, а затем прямой вывод буфера с помощью fwrite() / cout.write() (и аналогичное решение для ввода)
  • Экзотический способ посимвольного ввода/вывода: cin.rdbuf()->sgetc() и cout.rdbuf()->sputc()
  • Какие-либо манипуляции с размером буфера потоков (похоже, что в GCC iostreams для стандартных потоков игнорирует пользовательские установки насчёт этого). Это направление ещё можно исследовать потом.

Как это запустить у себя?

Надо скомпилировать программу, не забыв включить оптимизацию ( -O2 /Release), и запустить её с тем же рабочим каталогом, где она и находится. Если при запуске в Windows появляется сообщение Access denied, то может помочь запуск программы с повышенными правами. Программе потребуется пара сотен мегабайтов свободного места в каталоге для временных файлов.

Дополнительные замечания

  • Почему нужно для каждого теста создавать новый процесс?

Из-за ios_base::sync_with_stdio(false) , который препятствует поочерёдному тестированию stdio и iostreams, а также (теоретически) мешает использовать freopen() , чтобы перенаправлять cin / cout .

  • Зачем удалять файл от предыдущего запуска перед каждым тестом?

Чтобы все запуски были в равных условиях. Хотя, это несколько спорный вопрос. Может, лучше не удалять, а переписывать?

  • Почему время измеряет запускаемый, а не запускающий процесс?

Чтобы исключить время запуска/завершения процесса.

  • Почему бы вместо clock() не использовать более точные вызовы, например, getrusage() ?

Это можно. Но сначала мне надо понять, как это делать в Windows 🙂

Результаты

Запускал на компьютере с Pentium 4, так что время может показаться несколько большим.

  • Для Visual C++ 2010: http://pastie.org/4680309
int, printf 9.45 9.48 9.44 int, cout 22.03 22.01 22.21 int, custom/out 11.17 11.06 11.20 int, scanf 5.04 4.77 4.82 int, cin 20.26 20.16 20.16 int, custom/in 10.25 10.25 10.25 double, printf 19.23 18.98 18.95 double, cout 37.49 37.52 37.44 double, scanf 12.11 11.75 11.73 double, cin 26.88 26.57 26.57 char, putchar 13.29 13.76 13.48 char, cout 23.52 24.15 23.41 char, getchar 12.87 12.82 12.74 char, cin 16.13 16.22 16.50 char *, printf 6.88 6.74 6.57 char *, puts 3.95 3.82 3.95 char *, cout 6.36 6.32 6.43 string, cout 6.40 6.40 6.61 char *, scanf 6.16 6.10 6.13 char *, gets 3.98 3.96 3.96 char *, cin 8.72 8.91 8.85 string, getline 11.70 11.47 11.53

Здесь всё очевидно: stdio значительно превосходит по скорости iostreams. Примечательно, что на int printf() / scanf() быстрее даже самописных функций (однако см. дополнение ниже). Ввод/вывод строк с помощью puts() / gets() быстрее, чем с помощью printf() / scanf() — ну, это и понятно. Запись std::string занимает столько же, сколько и запись char * , а вот чтение в std::string медленнее — наверняка из-за необходимости динамически выделять память.

  • Для MinGW (GCC 4.7.0): http://pastie.org/4680314
int, printf 9.72 9.61 9.61 int, cout 6.08 6.05 6.10 int, custom/out 2.73 2.75 2.76 int, scanf 5.01 5.01 5.01 int, cin 3.99 4.04 4.04 int, custom/in 0.86 0.86 0.87 double, printf 22.51 22.40 22.42 double, cout 110.98 111.77 111.01 double, scanf 12.18 12.20 12.17 double, cin 118.87 118.84 118.87 char, putchar 1.67 1.65 1.64 char, cout 3.93 3.87 3.85 char, getchar 0.78 0.80 0.80 char, cin 3.29 3.31 3.29 char *, printf 5.55 5.47 5.49 char *, puts 5.37 5.32 5.41 char *, cout 8.72 8.72 8.78 string, cout 8.74 8.71 9.06 char *, scanf 7.07 7.04 7.02 char *, gets 3.84 3.79 3.77 char *, cin 5.30 5.38 5.35 string, getline 14.15 14.12 14.16

А здесь всё уже не так однозначно. Неожиданно оказывается, что iostreams на 20-30% быстрее stdio на int . Правда, самописные функции значительно обгоняют и то, и то. С double наоборот: iostreams заметно тормозит. Посимвольный ввод/вывод с putchar() / getchar() работает в 2-3 раза быстрее cout / cin . Ввод/вывод строк отличается не так сильно, но stdio и тут быстрее. На строках puts() / gets() также быстрее, чем printf() / scanf() . std::string , как и в предыдущем случае, работает одинаково с char * на выводе, однако медленнее на вводе.

Какие делать выводы и что использовать, пусть каждый решает сам. В комментариях приветствуется флейм конструктивное обсуждение.

Дополнение

В Visual C++ есть способ значительно ускорить базовые операции с потоками stdio, отключив блокировку потоков для функций getchar() , putchar() и некоторых других. Для этого надо перед всеми #include вставить строчку

#define _CRT_DISABLE_PERFCRIT_LOCKS

(описание). Это сработает только при выполнении следующих дополнительных условий:

  • Программа статически компонуется со стандартной библиотекой ( /MT ; на Codeforces, похоже, это так)
  • Программа включает , но не включает ни , ни какой-либо файл из библиотеки iostreams ( /…)

Вместо всей этой магии можно также просто использовать _putchar_nolock() / _getchar_nolock() вместо putchar() / getchar() . В Linux тоже есть похожие функции: ссылка.

С этой оптимизацией посимвольный ввод/вывод ускоряется в восемь-девять (!) раз, а вместе с ним и вручную написанные функции ввода/вывода int :

int, custom/out 1.70 1.70 1.72 int, custom/in 1.28 1.26 1.28 char, putchar 1.72 1.62 1.61 char, getchar 1.36 1.34 1.36

В MinGW такое поведение включено по умолчанию и не имеет вышеописанных ограничений.

Теги

c++, ввод-вывод, производительность

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *