0

I have implemented a container and running some tests on it. While on this I noticed this behaviour:

If I compile this (here cit is one of my containers):

//...
   int i = 0;
   while(i != 10)
     {
     std::cout << *cit << "  ";
     ++cit; ++i;
     }
//...

Then I print the data I expect:

me@LAPTOP-Q8SCO8V5:~/proj/proj_dev$ g++ main.cpp
me@LAPTOP-Q8SCO8V5:~/proj/proj_dev$ ./a.out
5  6  2  4  4  1  2  3  2  7

But then, if the condition is changed to this loop:

//...
   int i = 0;
   do {
     std::cout << *cit << "  ";
     ++cit; ++i;
   } while(cit != mit.end_row(0));
//...

I get a segfault:

me@LAPTOP-Q8SCO8V5:~/proj/proj_dev$ g++ main.cpp
me@LAPTOP-Q8SCO8V5:~/proj/proj_dev$ ./a.out
Segmentation fault (core dumped)

I know the loop might break (and probably is) because of some mistake I made implementing cit or mit.end_row. But in this example, I would expect at least to print that first element correctly before segfaulting. For the first snippet, I believe the container is initialized as I expect.

My question is if this behaviour I see is generated by the compiler, optimizing the code and finding it would eventually segfault. Or if something else I am missing.

If any implementation code for cit is needed, I will gladly provide. I didn't do so in my original post as I am not sure the question requires it being posted.

2 Answers2

3

std::cout is buffered - the output is stored into a memory cache instead of being printed immediately, and only displays when the buffer is "flushed". This allows your computer to optimize the program by waiting for a good time to use the output in a chunk instead of as single characters, such as waiting for the hard drive to be in position if you're writing to a file. (Imagine writing every character one at a time to your hard disk, that's slow!) However, there's no guarantees about when your machine will flush the buffer, unless you do it yourself.

In this case, the output is being loaded into the buffer, but since you never call std::cout.flush() or print a std::endl (which also flushes the buffer), you can't be sure the output will print before you segfault. After that happens, all bets are off.

Nick Reed
  • 4,989
  • 4
  • 17
  • 37
0

If *cit or mit.end_row(0) or operator!=() invokes undefined behaviour (for example, dereferencing one-past-the-end of your container), then it might appear to work sometimes, and other times hove bizarre and unexplained results.

You need to identify all undefined behaviour in your program and fix it.

Stephen M. Webb
  • 1,705
  • 11
  • 18