What's std::ios::sync_with_stdio(false) and std::cin.tie(nullptr)?

Share on:
800 Words | Read in about 4 Min | View times

Overview

You may often see the following calls std::ios::sync_with_stdio(false) and std::cin.tie(nullptr) in some online judge system, such as leetcode, poj, etc. Someone would tell you that these codes are usually used to speed up the execution time. But what is the exact meanings for these codes?

1static auto _ = []() {
2  std::ios::sync_with_stdio(false);
3  std::cin.tie(nullptr);
4  return nullptr;
5}();

These two calls have different meanings that have nonthing to do with performance. The fact that it speeds up code execution time is just a side effect.

Decoupling C and C++ streams

Function

1static bool std::ios::sync_with_stdio(bool sync = true);

Sets whether the standard C++ streams are synchronized to the standard C streams after each input/output operation.

The standard C++ streams are: std::cin, std::cout, std::cerr, std::clog, std::wcin, std::wcout, std::wcerr and std::wclog.

The standard C streams are: stdin, stdout and stderr.

By default, sync_with_stdio() has default value true, which means all standard streams are synchronized between C and C++ standard streams. In practice, it allows you to mix C and C++ style I/O and get expected results.

Example 1

 1#include <iostream>
 2#include <cstdio>
 3
 4int main() {
 5    std::cout << "a\n";
 6    std::printf("b\n");
 7    std::cout << "c\n";
 8    return 0;
 9}
10

In general, the result for the above example is:

1a
2b
3c

This is the default behavior in C++. The C stream stdout and C++ stream std::out are synchronized, they share the same I/O buffer. In fact, the C++ streams are unbuffered, and each I/O operaction on C++ streams is immediately applied to the corresponding C streams buffer. So it will result the correct order for all output.

Now let’s make some change.

Example 2

 1#include <iostream>
 2#include <cstdio>
 3
 4int main() {
 5    std::cout << "a\n";
 6    std::printf("b\n");
 7    std::cout << "c\n";
 8    return 0;
 9}
10
11static auto _ = []() {
12    std::ios::sync_with_stdio(false);
13    return nullptr;
14}();

You may get a possible output like this:

1b
2a
3c

Woops! The output result is no longer abc.

After set false to sync_with_stdio, the C streams and C++ streams are no longer synchronized. In fact, they will maintain indepedent buffers for their own, each I/O operation on C++ streams will not be applied to the corresponding C stream buffer now, which may be considerably faster than in some cases.

In addition, I’m not using std::endl to break line for std::cout, beacuse std::endl will flush the I/O buffer immediately which you won’t see what happen between the C and C++ streams synchronization.

Decoupling input and output streams

Function

1ostream* tie (ostream* tiestr);

The tied stream is an output stream object which is flushed before each I/O operation in this stream object.

By default, the standard stream std::cin and std::cerr are tied to std::cout, and std::wcin and std::wcerr are tied to std::wcout to ensure a sensible user interaction.

Example 1

 1#include <iostream>
 2#include <string>
 3
 4int main() {
 5    std::string name;
 6    std::cout << "What's your name:";
 7    std::cin >> name;
 8    std::cout << "Your name is " << name << std::endl;
 9    return 0;
10}

In gernal, the result for the above code is:

1What's your name:

After type my name:

1What's your name:zhxilin
2Your name is zhxilin

The standard input stream std::cin is tied to the output stream std::cout by default, which means before type my name to the input stream, the output stream buffer is flushed to the console. So you can see the sentence What's your name before any typing.

Now let’s make some change.

Example 2

 1#include <iostream>
 2#include <string>
 3
 4int main() {
 5    std::string name;
 6    std::cout << "What's your name:";
 7    std::cin >> name;
 8    std::cout << "Your name is " << name << std::endl;
 9    return 0;
10}
11
12static auto _ = []() {
13    std::ios::sync_with_stdio(false);
14    std::cin.tie(nullptr);
15    return nullptr;
16}();

You won’t see the sentance What's your name before any typing now. But after type my name, the result is:

1zhxilin
2What's your name:Your name is zhxilin

Therefore, if std::cin and std::cout are tied, you can expect the ouput to be flushed before the program prompts input for user. In this case, the output stream should be manually flushed or until the buffer is fulled. As for the side effect, some codes will speed up when execution for untied and non-synchronized streams.

Conclusion

  • Using std::ios::sync_with_stdio(false) is sufficient to decouple C and C++ streams.
  • Using std::cin.tie(nullptr) is sufficient to decouple std::cin and std::cout.
  • Speeding up I/O operation effeciency is only some side effects for calling these functions in some ACM-case.

References

Next Post: 『WSL2 Network Forwarding』