Why do we need to tie std::cin and std::cout?
There is nothing wrong in your example (except that you should add a semi-colon after the cin.tie(0)
line), nor with the way iostream objects work.
tie()
simply guarantees the flushing of cout
before cin
executes an input. This is useful for the user to see the question before being asked for the answer.
However, if you un-tie()
the cin
from cout
, there is no guarantee that the buffer of the cout
is flushed. But there is no guarantee that the buffer is un-flushed neither. In fact, if the computer has enough resources, it will flush the cout
buffer immediately, so this occurs before cin
asking for the input. This is the case in your example.
So, everything works well. Except that after cin.tie(0)
, there is no guarantee that the flush-ing will occur. However, in 99% of the cases, that flush-ing will still occur (but it is no longer guaranteed).
In theory, if tied, cin
and cout
could share the same buffer. But, I think no implementation does that. One reason is that the two may be un-tie()d.
Using std::endl vs \n when cin and cout are untied
how do I ensure that the buffer doesn't get overflowed,
The output buffer doesn't "overflow". When it gets full, it is automatically flushed, i.e. its contents are written out and its length is reset to 0. This is the case whether cin
/ cout
are tied or not.
cin and cout work properly without blocking
You normally want operations on cin
/ cout
to block. But again, blocking vs. non-blocking I/O has nothing to do with whether cin
/ cout
are tied.
and buffer gets flushed properly when I am not using std::endl. Does the use of "\n" automatically handles it?
Outputting '\n'
only flushes the buffer if the stream is in line-buffered mode. cout
is automatically put in line-buffered mode if output goes to a terminal; otherwise it is block buffered (i.e. it only gets flushed when it runs full).
In a programming competition cout
usually goes to a pipe or log file, so it will be block buffered and '\n'
doesn't cause a flush. However, in that situation it also doesn't matter whether prompts are displayed before input is read (which is the normal use case for tied cin
/ cout
). Just make sure you produce the right output and let the I/O library worry about buffering. The buffer is automatically flushed when it runs full, when the stream is closed, and when your program exits. No output is lost (unless your program crashes, but then you have other things to worry about).
How to prevent `std::cin` or `\n` from flushing the buffer of `std::cout`?
You could write to your own std::stringstream
buffer, and then output that to std::cout
when you're ready.
MWE:
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <vector>
using std::cin;
using std::cout;
using std::istream;
using std::runtime_error;
using std::stringstream;
using std::vector;
static auto get_int(istream& in) -> int {
int n;
if (!(in >> n)) {
throw runtime_error("bad input");
}
return n;
}
int main() {
auto ss = stringstream();
auto v = vector<int>();
auto size = get_int(cin);
while(size--) {
auto n1 = get_int(cin);
if (n1 == 0) {
auto n2 = get_int(cin);
v.push_back(n2);
} else if (n1 == 1) {
auto n2 = get_int(cin);
ss << v[n2] << '\n';
} else if (n1 == 2) {
v.pop_back();
}
}
cout << ss.str();
}
When i use cout.tie(NULL), program doesn't print anything for my code, but if i print endl, program works fine
std::cout
will flush under these conditions:
An input-stream which is tied to
std::cout
tries to read input.
You removed the ties.iostreams are synchronized with stdio, thus effectively unbuffered.
You disabled the synchronization.The buffer is full.
That takes a bit longer.The program ends normally.
That comes too late for you.There is a manual flush (
stream.flush()
which is called when streamingstd::flush
;stream << std::endl
is equivalent tostream << stream.widen('\n') << std::flush
).
You have none of those.
So, fix any of them and you will see your output earlier.
Is explicit flush necessary for interleaved cout and cin operations?
The stream std::cout
is tied to std::cin
by default: the stream pointed to by stream.tie()
is flushed prior to every properly implement input operation. Unless you changed the stream tied to std::cin
, there is no need to flush std::cout
before using std::cin
as it will be done implicitly.
The actual logic to flush the stream happens when constructing a std::istream::sentry
with an input stream: when the input stream isn't in failure state, the stream pointed to by stream.tie()
is flushed. Of course, this assumes that the input operators look something like this:
std::istream& operator>> (std::istream& in, T& value) {
std::istream::sentry cerberos(in);
if (sentry) {
// read the value
}
return in;
}
The standard stream operations are implemented this way. When user's input operations are not implemented in this style and do their input directly using the stream buffer, the flush won't happen. The error is, of course, in the input operators.
How is `std::cout` implemented?
how std::cout is created?
First things first, from https://en.cppreference.com/w/cpp/io/ios_base/Init :
std::ios_base::Init
This class is used to ensure that the default C++ streams (std::cin,
std::cout, etc.) are properly initialized and destructed. [...]The header
<iostream>
behaves as if it defines (directly or
indirectly) an instance of std::ios_base::Init with static storage
duration: [...]
Meh, let's do a real code example. I will be using GCC C++ library. From https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/iostream#L73 , this is the important part:
// For construction of filebuffers for cout, cin, cerr, clog et. al.
static ios_base::Init __ioinit;
Now we jump to the constructor of ios_base::Init
class, in https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/ios_init.cc#L85 :
ios_base::Init::Init()
{
if (__gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 1) == 0)
{
// Standard streams default to synced with "C" operations.
_S_synced_with_stdio = true;
new (&buf_cout_sync) stdio_sync_filebuf<char>(stdout);
new (&buf_cin_sync) stdio_sync_filebuf<char>(stdin);
new (&buf_cerr_sync) stdio_sync_filebuf<char>(stderr);
// The standard streams are constructed once only and never
// destroyed.
new (&cout) ostream(&buf_cout_sync);
new (&cin) istream(&buf_cin_sync);
new (&cerr) ostream(&buf_cerr_sync);
new (&clog) ostream(&buf_cerr_sync);
cin.tie(&cout);
cerr.setf(ios_base::unitbuf);
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 455. cerr::tie() and wcerr::tie() are overspecified.
cerr.tie(&cout);
The _S_refcount
is there for when you would call ios_base::Init::Init();
manually from a constructor of a static class, it protects against double initialization.
The stdio_sync_filebuf
is an internal buffer for istream
/ostream
and it is meant to handle cstdio
FILE*
operations to get/put input/output data, with implementation here https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/ext/stdio_sync_filebuf.h#L56 . It inherits from std::basic_streambuf
.
So cout
is constructed in-place with stdio_sync_filebuf<char>
as parameter. It is the first constructor mentioned here https://en.cppreference.com/w/cpp/io/basic_ostream/basic_ostream .
Now, because the stuff is constructed in-place, you might wonder how is the memory allocated? From https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/globals_io.cc#L50 :
// Standard stream objects.
// NB: Iff <iostream> is included, these definitions become wonky.
typedef char fake_istream[sizeof(istream)]
__attribute__ ((aligned(__alignof__(istream))));
typedef char fake_ostream[sizeof(ostream)]
__attribute__ ((aligned(__alignof__(ostream))));
fake_istream cin;
fake_ostream cout;
fake_ostream cerr;
fake_ostream clog;
The objects are just empty char
buffers of proper size and proper alignment.
And yes, you can construct ostream yourself, with __gnu_cxx::stdio_sync_filebuf
on GCC:
#include <fstream>
#include <ext/stdio_sync_filebuf.h>
int main() {
__gnu_cxx::stdio_sync_filebuf<char> mybuf_cout_sync(stdout);
std::ostream os(&mybuf_cout_sync);
os << "Hello world!\n";
return 0;
}
Or, to be portable, you would write your own class that inherits from std::streambuf
and construct ostream
from it yourself. There are many examples online, like for example here https://stackoverflow.com/a/51250032/9072753 .
Significance of ios_base::sync_with_stdio(false); cin.tie(NULL);
The two calls have different meanings that have nothing to do with performance; the fact that it speeds up the execution time is (or might be) just a side effect. You should understand what each of them does and not blindly include them in every program because they look like an optimization.
ios_base::sync_with_stdio(false);
This disables the synchronization between the C and C++ standard streams. By default, all standard streams are synchronized, which in practice allows you to mix C- and C++-style I/O and get sensible and expected results. If you disable the synchronization, then C++ streams are allowed to have their own independent buffers, which makes mixing C- and C++-style I/O an adventure.
Also keep in mind that synchronized C++ streams are thread-safe (output from different threads may interleave, but you get no data races).
cin.tie(NULL);
This unties cin
from cout
. Tied streams ensure that one stream is flushed automatically before each I/O operation on the other stream.
By default cin
is tied to cout
to ensure a sensible user interaction. For example:
std::cout << "Enter name:";
std::cin >> name;
If cin
and cout
are tied, you can expect the output to be flushed (i.e., visible on the console) before the program prompts input from the user. If you untie the streams, the program might block waiting for the user to enter their name but the "Enter name" message is not yet visible (because cout
is buffered by default, output is flushed/displayed on the console only on demand or when the buffer is full).
So if you untie cin
from cout
, you must make sure to flush cout
manually every time you want to display something before expecting input on cin
.
In conclusion, know what each of them does, understand the consequences, and then decide if you really want or need the possible side effect of speed improvement.
Related Topics
Find Two Elements in an Array That Sum to K
Invalid Initialization of Non-Const Reference with C++11 Thread
Specialization of 'Template<Class _Tp> Struct Std::Less' in Different Namespace
How to Set the Cout Locale to Insert Commas as Thousands Separators
Large Negative Integer Literals
Where Should Non-Member Operator Overloads Be Placed
When Should I Use the Keyword "Typename" When Using Templates
C++ Expression Must Have a Constant Value
Calculate System Time Using Rdtsc
Is Casting Std::Pair<T1, T2> Const& to Std::Pair<T1 Const, T2> Const& Safe
Inconsistent Strcmp() Return Value When Passing Strings as Pointers or as Literals
How to Load & Call a Vbscript Function from Within C++
Strange "Unsigned Long Long Int" Behaviour
How to Pass a Std::Function Object to a Function Taking a Function Pointer
Why Are the Return Values of These Doubles -1.#Ind
Qsqldatabase: Qmysql Driver Not Loaded on Ubuntu 15.04 64Bits