Search code examples
c++ofstream

ofstream: running index doesn't work


I want to write several lines to a file. Each line has an index (running index). My code is:

ofstream outputFile;
int index = 0;

outputFile << ++index << ") FirstLine" <<endl
           << ++index << ") SecondLine" <<endl
           ...
           << ++index << ") LastLine" <<endl;

Problem is that I get no running index. That is, all lines has the same index (which is the total lines number). So my questions are firstly, how does ofstream work (meaning why do I get the described result). Secondly, what should I do to get it work?


Solution

  • Firstly, how does ofstream work (meaning why do I get the described result)?

    According to the C++ standard (section 1.9, clause 15):

    Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

    If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent, the behavior is undefined.

    Applied to your case:

    • The evaluation of the ++index statements (which are operands to the << operator) is unsequenced.

    • ++index modifies the value of index, and therefore has a side effect on a scalar object.

    • As such, the behavior is undefined.

    Secondly, what should I do to get it work?

    One simple option would be to split the single large output expression into multiple lines, such that each ++index statement is on a separate line.

    Alternatively, you could both solve the problem and reduce repetition by using a loop.

    For example:

    #include <array>
    #include <iostream>
    #include <string>
    
    int main () {
      static const std::array<std::string, 3> lines = {
        "First line",
        "Second line",
        "Last line",
      };
    
      for (int i = 0; i < lines.size(); ++i) {
        std::cout << i + 1 << ") " << lines[i] << std::endl;
      }
    }
    

    Save this as example.cc, and compile using:

    clang++ -std=c++14 example.cc -o example
    

    Then run the example:

    $ ./example
    1) First line
    2) Second line
    3) Last line
    

    Note that this prints to standard output to simplify the example, but std::cout can be easily replaced with an instance of std::ofstream depending on your use case.