0

I am trying to write a function in my program that loads a huge text-file of 216,555 words and put them as strings into a set. This works properly, but as expected, it will hang for a few micro seconds while looping through the file. But there is something funky going on with my loop, and it's not behaving properly. Please take the time to read, I am sure there's a valid reason for this, but I have no idea what to search for.

The code, which is working by the way, is this:

ifstream dictionary;
dictionary.open("Dictionary.txt");

if(dictionary.fail())
{
    cout<<"Could not find Dictionary.txt. Exiting."<<endl;
    exit(0);
}
int i = 0;
int progress = 216555/50;
cout<<"Loading dictionary..."<<endl;
cout<<"<                                                  >"<<endl;
cout<<"<";
for(string line; getline(dictionary, line);)
{
    usleep(1); //Explanation below (not the hangtime)
    i++;
    if(i%progress == 0)
        cout<<"=";
    words.insert(line);
}

The for-loop gets every string from the file, and inserts them in the map. This is a console-application, and I want the user to see the progress. It's not much of a delay, but I wanted to do it anyway. If you don't understand the code, I'll try to explain.

When the program starts, it first prints out "Loading Dictionary...", and then a "<" and a ">" separated by 50 spaces. Then on the next line: "<" followed by a "=" for every 433 word it loops through (216555/50). The purpose of this is so the user can see the progress. The wanted output half way through the loop would be like this:

Loading dictionary...
<                                                  >
<=========================                         

My problem is: The correct output is shown, but not at the expected time. It prints out the full progress bar, but that only after it has hanged and are done with the loop. How is that possible? The correct number of '=' are shown, but they all pop out at the same time, AFTER it hangs for some microseconds. I added the usleep(1) to make the hangtime a bit longer, but the same thing happened. The if-statement clearly works, or the '=' would've never showed at all, but it feels like my program is stacking the cout-calls for after the entire loop.

The weirdest thing of all, is that the last cout<<"<"; before the for-loop starts, is also shown at the same time as the rest of its line; after the loop is finished. Why and how?

Sti
  • 8,275
  • 9
  • 62
  • 124

3 Answers3

3

You never flush the stream, so the output just goes into a buffer.

Change cout<<"="; to cout<<"="<<std::flush;

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
3

You need to flush the output stream.

cout << "=" << std::flush;
Gary
  • 5,642
  • 1
  • 21
  • 41
1

The program is "stacking the cout-calls". It's called output buffering, and every major operating system does it.

When in interactive mode (as your program is intended to be used), output is buffered by line; that is, it will be forced to the terminal when a newline is seen. You can also have block-buffered (fixed number of bytes between forced outputs; used when piping output) and unbuffered.

C++ provides the std::flush stream modifier to force an output at any point. It can be used like this:

cout << "=" << std::flush;

This will slow down your program a bit; the point of buffering is for efficiency. As you'll only be doing it about 51 times, though, the slowdown should be negligible.

  • Thank you! Do you also happen to know if it's possible to print out something before something that has already been printed out? I would like the output to be one line as `<=== - >`, where the user can see the end of the progressbar while it runs, but that is impossible unless the entire line is printed out each time.. Do you get what I mean, and perhaps know what I should search for? – Sti Apr 23 '13 at 04:27
  • By the way, I found it. I just put '\r' behind the string, and it overwrites.(not in Xcode) – Sti Apr 23 '13 at 05:20
  • Yes, a carriage return (`\r`) resets the cursor to the start of the line, allowing you to overwrite the line. (Keep in mind that it doesn't automatically overwrite the line.) – michaelb958--GoFundMonica Apr 23 '13 at 11:57