Значение ios_base :: sync_with_stdio (false); cin.tie (NULL);

175

Какое значение имеет включение

ios_base::sync_with_stdio(false);
cin.tie(NULL);

в программах на C ++?

В моих тестах это ускоряет время выполнения, но есть ли тестовый пример, о котором я должен беспокоиться, включив его?

Всегда ли 2 утверждения должны быть вместе, или первого достаточно, т. Е. Игнорировать cin.tie(NULL)?

Кроме того, допустимо ли использовать одновременно команды C и C ++, если для него установлено значение false?

https://www.codechef.com/viewsolution/7316085

Приведенный выше код работал нормально, пока я не использовал scanf/printfв программе на C ++ значение как true. В этом случае он дал ошибку сегментации. Что может быть этому объяснению?

Кшитий Коли
источник
Вы действительно использовали это с ложью. В вашем коде так сказано ???
Сурадж Джайн

Ответы:

276

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

ios_base::sync_with_stdio(false);

Это отключает синхронизацию между стандартными потоками C и C ++. По умолчанию все стандартные потоки синхронизируются, что на практике позволяет смешивать ввод-вывод в стилях C и C ++ и получать разумные и ожидаемые результаты. Если вы отключите синхронизацию, потокам C ++ разрешено иметь свои собственные независимые буферы, что делает смешивание ввода-вывода в стилях C и C ++ приключением.

Также имейте в виду, что синхронизированные потоки C ++ являются потокобезопасными (вывод из разных потоков может чередоваться, но вы не получаете гонок за данные).

cin.tie(NULL);

Это развязывает cinот cout. Связанные потоки гарантируют, что один поток автоматически очищается перед каждой операцией ввода-вывода в другом потоке.

По умолчанию cinпривязан для coutобеспечения разумного взаимодействия с пользователем. Например:

std::cout << "Enter name:";
std::cin >> name;

Если cinи coutсвязаны, вы можете ожидать, что вывод будет сброшен (т.е. станет видимым на консоли) до того, как программа запросит ввод от пользователя. Если вы развяжете потоки, программа может заблокировать ожидание, пока пользователь введет свое имя, но сообщение «Введите имя» еще не отображается (поскольку coutпо умолчанию оно буферизуется, вывод сбрасывается / отображается на консоли только по запросу или когда буфер заполнен).

Так что, если вы отвязываетесь cinот cout, вы должны обязательно промывать coutвручную каждый раз, когда хотите что-то отобразить, прежде чем ожидать ввода cin.

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

Ионут
источник
Когда вы говорите «вы должны обязательно сбрасывать cout вручную каждый раз, когда хотите отобразить что-либо, прежде чем ожидать ввода в cin», это может быть так же просто, как добавление «... << std :: flush» или «... < <std :: endl "до конца каждой строки, начинающейся с" std :: cout << ... ", верно?
Алан
5
Да, это так просто, но будьте осторожны с частью «конец каждой строки». coutБуферизуется по какой-то причине, если вы слишком часто очищаете его, когда он вам на самом деле не нужен, вы можете увидеть снижение производительности.
Ionut
@Ionut есть ли что-то эквивалентное функции tie () в C для scanf, printf?
iajnr
2
@iajnr Нет, не напрямую. В C вы можете либо очистить вручную scanf(), либо полностью отключить буферизацию, либо переключиться на буферизацию строки (которая должна сбрасываться после новой строки или при чтении ввода stdin- см. Linux.die.net/man/3/setlinebuf ).
Ionut
2
На leetcode это значительно улучшает время выполнения, возможно, эти конкурирующие веб-сайты делают что-то особенное для входных тестов.
P0W
25

Это сделано для синхронизации операций ввода-вывода из мира C и C ++. Если вы синхронизируете, то у вас есть гарантия, что заказы всех операций ввода-вывода соответствуют вашим ожиданиям. В общем, проблема заключается в буферизации операций ввода-вывода, которая вызывает проблему, поскольку синхронизация позволяет обоим мирам использовать одни и те же буферы. Например cout << "Hello"; printf("World"); cout << "Ciao";; без синхронизации никогда не узнаешь, получишь ли HelloCiaoWorldили HelloWorldCiaoили WorldHelloCiao...

tieпозволяет вам иметь гарантию, что каналы ввода-вывода в мире C ++ связаны друг с другом, что означает, например, что каждый вывод был сброшен до того, как происходит ввод (подумайте об этом cout << "What's your name ?"; cin >> name;).

Вы всегда можете смешивать операции ввода-вывода C или C ++, но если вы хотите разумного поведения, вы должны синхронизировать оба мира. Помните, что вообще не рекомендуется смешивать их, если вы программируете на C, используйте C stdio, а если вы программируете на C ++, используйте потоки. Но вы можете смешать существующие библиотеки C с кодом C ++, и в этом случае необходимо синхронизировать оба.

Жан-Батист Юнес
источник
5
Даже без синхронизации разные вызовы cout <<не могут изменить порядок, поэтому CiaoHelloWorldв вашем примере это невозможно. Синхронизация касается строго различных методов буферизации.
Микко Ранталайнен 07
я даже не знаю, правда ли это, но я проголосовал за объяснение
Давуд Сеферли
4

Используя ios_base::sync_with_stdio(false);достаточно , чтобы отделить Cи C++потоки. Вы можете найти обсуждение этого в Стандартных C ++ IOStreams and Locales , написанных Лангером и Крефтом. Они отмечают, что то, как это работает, определяется реализацией.

В cin.tie(NULL)Вызов , кажется, запрашивающим развязку между деятельностью по cinи cout. Я не могу объяснить, почему использование этого с другой оптимизацией должно вызывать сбой. Как уже отмечалось, предоставленная вами ссылка плохая, поэтому здесь нет никаких предположений.

Дон Уэйкфилд
источник
1

Это обычная штука для изготовления cin ускорить ввод .

Для быстрого объяснения: первая строка отключает синхронизацию буфера между потоком cin и инструментами stdio в стиле C (такими как scanf или gets) - поэтому cin работает быстрее, но вы не можете использовать его одновременно с инструментами stdio .

Вторая строка отвязывает cin от cout - по умолчанию буфер cout очищается каждый раз, когда вы читаете что-то из cin . И это может быть медленным, когда вы постоянно читаете что-то маленькое, а затем много раз пишете что-то маленькое. Таким образом, строка отключает эту синхронизацию (буквально привязывая cin к нулю вместо cout ).

Сравья
источник
1

Лот отличного ответа. Я просто хочу добавить небольшую заметку о разделении потока .

cin.tie(NULL);

Я столкнулся с проблемой при развязке потока с помощью CodeChef платформой . Когда я отправил свой код, платформа ответила «Неверный ответ», но после привязки потока и тестирования отправки. Это сработало.

Итак, если кто-то хочет отвязать поток, выходной поток должен быть сброшен.

Изменить: я не знаком со всей платформой, но это то, что я испытал.

ashiish.me
источник