Ý nghĩa của ios_base :: sync_with_stdio (sai); cin.tie (NULL);


145

Tầm quan trọng của việc bao gồm

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

trong chương trình C ++?

Trong các thử nghiệm của tôi, nó tăng tốc thời gian thực hiện, nhưng có trường hợp thử nghiệm nào tôi nên lo lắng bằng cách bao gồm điều này không?

Làm 2 câu lệnh luôn phải ở cùng nhau, hoặc là câu đầu tiên đủ, nghĩa là bỏ qua cin.tie(NULL) ?

Ngoài ra, có được phép sử dụng đồng thời các lệnh C và C ++ nếu giá trị của nó đã được đặt thành false không?

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

Đoạn mã trên làm việc tốt, cho đến khi tôi sử dụng scanf/printftrong một chương trình C ++ có giá trị như true. Trong trường hợp này, nó đã đưa ra một lỗi phân khúc. Điều gì có thể là lời giải thích có thể cho điều này?


Bạn thực sự đã sử dụng nó với false. Mã của bạn nói vậy ???
Suraj Jain

Câu trả lời:


231

Hai cuộc gọi có ý nghĩa khác nhau không liên quan đến hiệu suất; thực tế là nó tăng tốc thời gian thực hiện (hoặc có thể ) chỉ là một tác dụng phụ. Bạn nên hiểu những gì mỗi người trong số họ làm và không mù quáng đưa chúng vào mọi chương trình vì chúng trông giống như một sự tối ưu hóa.

ios_base::sync_with_stdio(false);

Điều này vô hiệu hóa đồng bộ hóa giữa các luồng tiêu chuẩn C và C ++. Theo mặc định, tất cả các luồng tiêu chuẩn được đồng bộ hóa, trong thực tế cho phép bạn kết hợp I / O kiểu C- và C ++ và nhận được kết quả hợp lý và mong đợi. Nếu bạn vô hiệu hóa đồng bộ hóa, thì các luồng C ++ được phép có bộ đệm độc lập của riêng chúng, điều này làm cho việc trộn I / O theo kiểu C- và C ++ trở thành một cuộc phiêu lưu.

Ngoài ra, hãy nhớ rằng các luồng C ++ được đồng bộ hóa là an toàn cho luồng (đầu ra từ các luồng khác nhau có thể xen kẽ, nhưng bạn không nhận được các cuộc đua dữ liệu).

cin.tie(NULL);

Điều này cởi trói cintừcout . Các luồng bị ràng buộc đảm bảo rằng một luồng được xóa tự động trước mỗi hoạt động I / O trên luồng khác.

Theo mặc định cinđược gắn coutđể đảm bảo tương tác người dùng hợp lý. Ví dụ:

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

Nếu cincoutbị ràng buộc, bạn có thể mong đợi đầu ra được xóa (nghĩa là hiển thị trên bàn điều khiển) trước khi chương trình nhắc nhập từ người dùng. Nếu bạn gỡ các luồng, chương trình có thể chặn người dùng nhập tên của họ nhưng thông báo "Nhập tên" vẫn chưa hiển thị (vìcout được đệm theo mặc định, đầu ra bị xóa / hiển thị trên bảng điều khiển theo yêu cầu hoặc khi đệm đầy).

Vì vậy, nếu bạn gỡ bỏ cintừ đó cout, bạn phải đảm bảo tuôn ra coutthủ công mỗi khi bạn muốn hiển thị một cái gì đó trước khi mong đợi đầu vào cin.

Để kết luận, hãy biết những gì mỗi người trong số họ làm, hiểu hậu quả và sau đó quyết định xem bạn có thực sự muốn hoặc cần tác dụng phụ có thể của cải thiện tốc độ hay không.


Khi bạn nói "bạn phải đảm bảo xả cout thủ công mỗi lần bạn muốn hiển thị thứ gì đó trước khi mong đợi đầu vào trên cin", điều đó có thể đơn giản như nối thêm "... << std :: flush" hoặc "... < <std :: endl "đến cuối mỗi dòng bắt đầu" std :: cout << ... ", phải không?
Alan

4
Vâng, nó đơn giản như vậy, nhưng hãy cẩn thận với phần "cuối mỗi dòng". coutđược đệm vì một lý do, nếu bạn xả nó quá thường xuyên, khi bạn không thực sự cần nó, bạn có thể thấy một hiệu suất thành công.
Iovy

@ Tôi có một cái gì đó tương đương với chức năng tie () trong C cho scanf, printf?
iajnr

1
@iajnr Không, không trực tiếp. Trong C, bạn có thể xóa thủ công trước scanf(), tắt hoàn toàn bộ đệm hoặc chuyển sang bộ đệm dòng (sẽ xóa sau dòng mới hoặc khi đầu vào được đọc từ stdin- xem linux.die.net/man/3/setlinebuf ).
Irika

1
Tại leetcode, nó cải thiện đáng kể thời gian chạy, có thể các trang web cạnh tranh này làm điều gì đó đặc biệt cho các bài kiểm tra đầu vào.
P0W

17

Điều này là để đồng bộ hóa IO từ thế giới C và C ++. Nếu bạn đồng bộ hóa, thì bạn có một đảm bảo rằng các đơn đặt hàng của tất cả các IO là chính xác những gì bạn mong đợi. Nói chung, vấn đề là bộ đệm của IO gây ra sự cố, đồng bộ hóa cho phép cả hai thế giới chia sẻ cùng một bộ đệm. Ví dụ cout << "Hello"; printf("World"); cout << "Ciao";; mà không cần đồng bộ hóa, bạn sẽ không bao giờ biết nếu bạn sẽ nhận được HelloCiaoWorldhoặc HelloWorldCiaohoặcWorldHelloCiao ...

tiecho phép bạn đảm bảo rằng các kênh IO trong thế giới C ++ được liên kết với nhau, điều đó có nghĩa là mọi đầu ra đều bị xóa trước khi đầu vào xảy ra (nghĩ vềcout << "What's your name ?"; cin >> name; ).

Bạn luôn có thể trộn các IO C hoặc C ++, nhưng nếu bạn muốn một số hành vi hợp lý, bạn phải đồng bộ hóa cả hai thế giới. Xin lưu ý rằng nói chung không nên trộn chúng, nếu bạn lập trình trong C sử dụng C stdio và nếu bạn lập trình trong C ++, hãy sử dụng luồng. Nhưng bạn có thể muốn trộn các thư viện C hiện có vào mã C ++ và trong trường hợp đó cần phải đồng bộ hóa cả hai.


3
Ngay cả khi không đồng bộ hóa, các cuộc gọi khác nhau để cout <<không thể thay đổi thứ tự vì vậy CiaoHelloWorldkhông thể thực hiện được cho trường hợp ví dụ của bạn. Đồng bộ hóa là nghiêm ngặt về các phương pháp đệm khác nhau.
Mikko Rantalainen

3

Sử dụng ios_base::sync_with_stdio(false);là đủ để tách CC++các luồng. Bạn có thể tìm thấy một cuộc thảo luận về điều này trong Standard C ++ IOStreams và Locales , bởi Langer và Kreft. Họ lưu ý rằng làm thế nào điều này hoạt động được xác định thực hiện.

Cuộc cin.tie(NULL)gọi dường như đang yêu cầu tách rời giữa các hoạt động trên cincout. Tôi không thể giải thích tại sao sử dụng điều này với tối ưu hóa khác sẽ gây ra sự cố. Như đã lưu ý, liên kết bạn cung cấp là xấu, vì vậy không có suy đoán ở đây.


0

Nó chỉ là công cụ phổ biến để làm cho đầu vào cin hoạt động nhanh hơn.

Để giải thích nhanh: dòng đầu tiên tắt đồng bộ hóa bộ đệm giữa luồng cin và các công cụ stdio kiểu C (như scanf hoặc get) - vì vậy cin hoạt động nhanh hơn, nhưng bạn không thể sử dụng đồng thời với stdio các công cụ .

Dòng thứ hai cởi trói cho cin từ cout - theo mặc định, bộ đệm cout tuôn ra mỗi khi bạn đọc thứ gì đó từ cin . Và điều đó có thể chậm khi bạn liên tục đọc một cái gì đó nhỏ sau đó viết một cái gì đó nhỏ nhiều lần. Vì vậy, dòng tắt đồng bộ hóa này (bằng cách buộc cin thành null thay vì cout ).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.