One problem is that partial output gets displayed, which could look ugly.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
std::string get_name()
{
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return "Ninja";
}
std::string get_place()
{
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return "Paris";
}
int main()
{
std::cerr << "Hello " << get_name() << "! Nice meeting you here in " << get_place() << ".\n";
// ^^^^
// Replace with cout and see the difference!
}
| |
Here I have used cerr because it is unbuffered (output gets flushed right away). Sometimes functions take a little while to complete so to simulate that I added a "sleep" in get_name() and get_place().
If you run this you will see the output appear in steps:
"Hello "
"Hello Ninja! Nice meeting you here in "
"Hello Ninja! Nice meeting you here in Paris."
If you change cerr to cout (which is buffered) you'll see everything gets outputted at the same time, at the end, which looks much nicer.
Another problem is if you draw something on top of something else. This can be done more nicely using third-party libraries (e.g. with something like ncurses) but I have tried to hack something together to demonstrate the problem using only standard C++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
int main()
{
std::string animation[] =
{
" o-o> M ",
" o-o> M ",
" o-o> M ",
" o-o> M ",
" o-o> M ",
" o-o> M ",
" o-o>M ",
" **** ",
" *BANG* ",
" **BANG** ",
" *BANG* ",
" **** ",
" ** ",
" ",
" THE END ",
};
for (const std::string& frame : animation)
{
// return to start of line
std::cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
// display frame
for (char ch : frame)
{
std::cout << ch;
std::cout << std::flush; // remove this line and see the difference!
std::this_thread::sleep_for(std::chrono::milliseconds(30));
}
std::cout << std::flush;
// Change this number to control the speed of the animation.
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
| |
This is a small program that shows a simple animation of a car crashing.
I flush after each character and to make the problem more obvious I also "sleep" for 20 ms.
The problem is that in the process of drawing one frame on top of another you see two partial frames. This could be even more disturbing when the frames are more different.
The caret might make it look extra ugly, but there is no way hide it using only standard C++.
Remove the flush on line 36 and you'll see that the animation runs more smoothly.
A perhaps more common situation, where it appears like you're "overwriting" but you're not, is when outputting a fixed number of lines repeatedly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Avoid automatic flushing at the end of lines
// (You might not notice the difference since the
// lines are outputted so quickly after each other)
std::ios::sync_with_stdio(false);
int altitude = 2000;
int time_since_takeoff = 20;
while (true)
{
altitude += rand() % 21 - 10;
++time_since_takeoff;
std::cout << "\n\n";
std::cout << "Aircraft: Airbus A380\n";
std::cout << "Passangers : 242\n";
std::cout << "Altitude: " << altitude << " m\n";
std::cout << "Departure: Amsterdam, The Netherlands\n";
std::cout << "Desitnation: Oslo, Norway\n";
std::cout << "Time since takeoff: " << time_since_takeoff << " min \n";
std::cout << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
| |
Once the output has reached the bottom of the output window it will look sort of like the text is being updated because the new lines will appear where the old lines were.
Again, if you insert a flush and a small delay between outputting two lines (to simulate that you're calling some costly function while outputting) you'll see that it doesn't look as nice.