Значення ios_base :: sync_with_stdio (помилково); cin.tie (NULL);


146

Яке значення в тому числі

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

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

У моїх тестах це прискорює час виконання, але чи є тестовий випадок, про який я повинен турбуватися, включивши це?

Чи завжди два твердження повинні бути разом, або перше достатнє, тобто ігнорування cin.tie(NULL)?

Також, чи допустимо одночасне використання команд C і C ++, якщо його значення встановлено false?

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

Вищевказаний код працював чудово, поки я не використовував scanf/printfу програмі C ++ зі значенням як true. У цьому випадку він дав помилку сегментації. Що може бути можливим поясненням цього?


Ви насправді використовували це з помилковим. Ваш код говорить так ???
Сурай Джайн

Відповіді:


231

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

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 << ... ", так?
Алан

4
Так, це так просто, але будьте обережні з частиною "в кінці кожного рядка". coutбуферизована з причини, якщо ви змиваєте її занадто часто, коли вам це фактично не потрібно, ви можете побачити хіт продуктивності.
Іонут

@Ionut чи є щось еквівалентне функціоналу tie () в C для scanf, printf?
iajnr

1
@iajnr Ні, не безпосередньо. У програмі C ви можете будь-коли промити вручну scanf(), повністю відключити буферизацію або переключитися на буферизацію ліній (яка повинна спускатися після нового рядка або при зчитуванні входу stdin- див. Linux.die.net/man/3/setlinebuf ).
Іонут

1
У Leetcode це значно покращує час виконання, можливо, ці конкурентні веб-сайти роблять щось особливе для вхідних тестів.
P0W

18

Це для синхронізації IO з C та C ++ світу. Якщо ви синхронізуєтесь, то ви маєте гарантію, що замовлення всіх МО саме те, що ви очікуєте. Взагалі проблема полягає в буферизації вводу-виводу, що викликає проблему, синхронізація дозволяє обом світам ділити однакові буфери. Наприклад cout << "Hello"; printf("World"); cout << "Ciao";; без синхронізації ви ніколи не будете знати , якщо ви отримаєте HelloCiaoWorldабо HelloWorldCiaoабо WorldHelloCiao...

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

Ви завжди можете змішувати C або C ++ IO, але якщо ви хочете певної поведінки, ви повинні синхронізувати обидва світи. Будьте уважні, що взагалі їх не рекомендується змішувати, якщо ви програмуєте на C, використовуйте C stdio, а якщо ви програмуєте на C ++, використовуйте потоки. Але ви, можливо, захочете змішати існуючі бібліотеки C у код C ++, і в такому випадку потрібно синхронізувати обидва.


4
Навіть без синхронізації різні дзвінки не cout <<можуть змінити порядок, тому CiaoHelloWorldнеможливо для вашого прикладу. Синхронізація суворо стосується різних методів буферизації.
Мікко Ранталайнен

3

Використання ios_base::sync_with_stdio(false);достатньо для роз'єднання потоків Cта C++потоків. Ви можете знайти обговорення цього питання в стандартних C ++ IOStreams та Locales , Langer та Kreft. Вони зазначають, що, як це працює, визначено впровадження.

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


0

Це просто звичайні речі для того, щоб швидше працювати з введенням cin .

Для швидкого пояснення: перший рядок вимикає буферну синхронізацію між потоком cin та інструментами stdio у стилі C (на зразок scanf або get ) - таким чином cin працює швидше, але ви не можете його використовувати одночасно зі stdio інструментами.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.