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


146

Apa pentingnya termasuk

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

dalam program C ++?

Dalam pengujian saya, ini mempercepat waktu eksekusi, tetapi apakah ada ujian yang harus saya khawatirkan dengan memasukkan ini?

Apakah 2 pernyataan selalu harus bersama, atau yang pertama cukup, yaitu mengabaikan cin.tie(NULL)?

Juga, apakah diizinkan untuk menggunakan perintah C dan C ++ secara simultan jika nilainya telah disetel ke false?

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

Kode di atas bekerja dengan baik, sampai saya gunakan scanf/printfdalam program C ++ dengan nilai as true. Dalam hal ini, ia memberikan kesalahan segmentasi. Apa yang mungkin menjadi penjelasan untuk ini?


Anda benar-benar menggunakannya dengan false. Kode Anda mengatakan demikian ???
Suraj Jain

Jawaban:


231

Kedua panggilan memiliki arti berbeda yang tidak ada hubungannya dengan kinerja; fakta bahwa itu mempercepat waktu eksekusi adalah (atau mungkin ) hanya efek samping. Anda harus memahami apa yang masing-masing dari mereka lakukan dan tidak secara membabi buta memasukkan mereka dalam setiap program karena mereka terlihat seperti sebuah optimasi.

ios_base::sync_with_stdio(false);

Ini menonaktifkan sinkronisasi antara aliran standar C dan C ++. Secara default, semua stream standar disinkronkan, yang dalam praktiknya memungkinkan Anda untuk mencampur C / C dan C ++ - gaya I / O dan mendapatkan hasil yang masuk akal dan diharapkan. Jika Anda menonaktifkan sinkronisasi, maka aliran C ++ diizinkan memiliki buffer independennya sendiri, yang menjadikan pencampuran C / dan C ++ - gaya I / O menjadi petualangan.

Perlu diingat juga bahwa aliran C ++ yang disinkronkan aman-thread (output dari utas yang berbeda mungkin saling berhubungan, tetapi Anda tidak mendapatkan balapan data).

cin.tie(NULL);

Ini terlepas cindari cout. Aliran yang diikat memastikan bahwa satu aliran disiram secara otomatis sebelum setiap operasi I / O pada aliran lainnya.

Secara default cinterkait dengan coutuntuk memastikan interaksi pengguna yang masuk akal. Sebagai contoh:

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

Jika cindan coutterikat, Anda dapat mengharapkan output memerah (yaitu, terlihat pada konsol) sebelum program meminta input dari pengguna. Jika Anda membatalkan streaming, program mungkin memblokir menunggu pengguna untuk memasukkan nama mereka tetapi pesan "Masukkan nama" belum terlihat (karena coutbuffered secara default, output memerah / ditampilkan pada konsol hanya atas permintaan atau ketika buffer sudah penuh).

Jadi, jika Anda melepaskan cindari cout, Anda harus memastikan untuk menyiram coutsecara manual setiap kali Anda ingin menampilkan sesuatu sebelum mengharapkan input aktif cin.

Sebagai kesimpulan, ketahui apa yang mereka masing-masing lakukan, pahami konsekuensinya, dan kemudian putuskan apakah Anda benar-benar menginginkan atau membutuhkan efek samping yang mungkin dari peningkatan kecepatan.


Ketika Anda mengatakan "Anda harus memastikan flush cout secara manual setiap kali Anda ingin menampilkan sesuatu sebelum mengharapkan input pada cin", itu bisa sesederhana menambahkan "... << std :: flush" atau "... < <std :: endl "hingga akhir setiap baris yang dimulai" std :: cout << ... ", kan?
Alan

4
Ya, sesederhana itu, tetapi hati-hati dengan bagian "akhir setiap baris". coutbuffered karena suatu alasan, jika Anda menyiramnya terlalu sering, ketika Anda tidak benar-benar membutuhkannya, Anda mungkin akan melihat peningkatan kinerja.
Ionut

@Ionut apakah ada sesuatu yang setara dengan fungsi tie () di C untuk scanf, printf?
iajnr

1
@iajnr Tidak, tidak secara langsung. Di C, Anda dapat membersihkan secara manual sebelumnya scanf(), menonaktifkan buffering sepenuhnya atau beralih ke buffering baris (yang seharusnya siram setelah baris baru atau ketika input dibaca dari stdin- lihat linux.die.net/man/3/setlinebuf ).
Ionut

1
Pada leetcode, ini secara signifikan meningkatkan runtime, mungkin situs web yang kompetitif ini melakukan sesuatu yang istimewa untuk pengujian input.
P0W

17

Ini untuk menyinkronkan IO dari dunia C dan C ++. Jika Anda menyinkronkan, maka Anda memiliki jaminan bahwa pesanan semua IO persis seperti yang Anda harapkan. Secara umum, masalahnya adalah buffering IO yang menyebabkan masalah, sinkronisasi memungkinkan kedua dunia untuk berbagi buffer yang sama. Misalnya cout << "Hello"; printf("World"); cout << "Ciao";; tanpa sinkronisasi Anda tidak akan pernah tahu apakah Anda akan mendapatkan HelloCiaoWorldatau HelloWorldCiaoatau WorldHelloCiao...

tiememungkinkan Anda memiliki jaminan bahwa saluran IOs di dunia C ++ terikat satu sama lain, yang berarti misalnya setiap output telah memerah sebelum input terjadi (pikirkan cout << "What's your name ?"; cin >> name;).

Anda selalu dapat mencampurkan C atau C ++ IO, tetapi jika Anda menginginkan perilaku yang masuk akal, Anda harus menyinkronkan kedua dunia. Hati-hati bahwa secara umum tidak disarankan untuk mencampurnya, jika Anda memprogram dalam C menggunakan C stdio, dan jika Anda memprogram dalam C ++ gunakan stream. Tetapi Anda mungkin ingin menggabungkan pustaka C yang ada ke dalam kode C ++, dan dalam kasus seperti itu diperlukan untuk menyinkronkan keduanya.


3
Bahkan tanpa sinkronisasi, panggilan berbeda untuk cout <<tidak dapat mengubah urutan sehingga CiaoHelloWorldtidak mungkin untuk contoh kasus Anda. Sinkronisasi hanya tentang metode buffering yang berbeda.
Mikko Rantalainen

3

Menggunakan ios_base::sync_with_stdio(false);cukup untuk memisahkan Cdan C++stream. Anda dapat menemukan diskusi ini di Standard C ++ IOStreams dan Locales , oleh Langer dan Kreft. Mereka mencatat bahwa cara kerjanya ditentukan oleh implementasi.

The cin.tie(NULL)panggilan tampaknya meminta decoupling antara kegiatan di cindan cout. Saya tidak bisa menjelaskan mengapa menggunakan ini dengan optimasi lain harus menyebabkan crash. Seperti yang disebutkan, tautan yang Anda berikan buruk, jadi tidak ada spekulasi di sini.


0

Itu hanya hal biasa untuk membuat input cin bekerja lebih cepat.

Untuk penjelasan singkat: baris pertama mematikan sinkronisasi buffer antara stream cin dan alat stdio C-style (seperti scanf atau get) - jadi cin bekerja lebih cepat, tetapi Anda tidak dapat menggunakannya secara bersamaan dengan alat stdio .

Baris kedua melepaskan ikatan cin dari cout - secara default buffer cout memerah setiap kali Anda membaca sesuatu dari cin . Dan itu mungkin lambat ketika Anda berulang kali membaca sesuatu yang kecil kemudian menulis sesuatu yang kecil berkali-kali. Jadi garis mematikan sinkronisasi ini (dengan secara harfiah mengikat cin ke null, bukan cout ).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.