11

According to this C++ reference: http://www.cplusplus.com/reference/fstream/ofstream/ofstream/, the default open mode for std::ofstream is ios_base::out and it mentions no implict other modes. Therefore I would expect that if I overwrite a large file with a small file, the "exceeding" part of the large file should stay untouched and only the first part of the file should be replaced by the new, shorter data.

On the other hand, the Apache C++ Standard Library User's Guide (http://stdcxx.apache.org/doc/stdlibug/30-3.html) states in the note to paragraph 30.3.1.2: "For output file streams the open mode out is equivalent to out|trunc, that is, you can omit the trunc flag. For bidirectional file streams, however, trunc must always be explicitly specified."

I have tried this code:

#include <fstream>

int main()
{
    std::ofstream aFileStream("a.out", std::ios_base::out);
    aFileStream << "Hello world!";
    aFileStream.close();

    std::ofstream aFileStream2("a.out", std::ios::out);
    aFileStream2 << "Bye!";
    aFileStream2.close();
}

Both, with g++ 8.1 on Windows and g++ 6.3 on Linux, the Apache documentation seems to be right. The large file is truncated, nothing remains after writing the shorter string with the second file stream.

Why is it like that? Is cplusplus.com wrong? Or on what does the behaviour depent?

Benjamin Bihler
  • 1,612
  • 11
  • 32
  • According to [cppreference](https://en.cppreference.com/w/cpp/io/basic_filebuf/open) the out will delete content on already existing files (so overriding everything) – DColt Jul 17 '19 at 06:54

1 Answers1

12

Per [ofstream.cons]/itemdecl:2:

explicit basic_ofstream(const char* s,
                        ios_base::openmode mode = ios_base::out);

Therefore, the default mode for ofstream is out. However, per [tab:filebuf.open.modes], out and out | trunc both correspond to the stdio equivalent "w", so they are equivalent. Per C11 7.21.5.3:

w: truncate to zero length or create text file for writing

Thus, it is correct to say that the default mode is out, and it is also correct to say that the default mode is equivalent to out | trunc. This is guaranteed behavior.

On the other hand, per [fstream.cons]/itemdecl:2:

explicit basic_fstream(
  const char* s,
  ios_base::openmode mode = ios_base::in | ios_base::out);

Therefore, the default mode for fstream is in | out. Per [tab:filebuf.open.modes], in | out corresponds to "r+", while in | out | trunc corresponds to "w+", so they are not equivalent. Per C11 7.21.5.3:

r+: open text file for update (reading and writing)
w+: truncate to zero length or create text file for update

Therefore, fstream does not truncate unless you specify trunc. Note that if the desired file does not exist, r+ will fail instead of creating the file. In contrast, w and w+ both create a new file in this case.

(See also: fopen on cppreference)

Felix Dombek
  • 13,664
  • 17
  • 79
  • 131
L. F.
  • 19,445
  • 8
  • 48
  • 82
  • Great answer – Could you also link the quoted C standard? That would make the answer even better. – Felix Dombek Jul 17 '19 at 07:46
  • @FelixDombek Unfortunately, I am not aware of an official HTML C standard draft version. The PDF version of the C11 final draft is available at http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. Wait a sec ... – L. F. Jul 17 '19 at 07:48
  • 1
    @FelixDombek Added link to standard and cppreference. – L. F. Jul 17 '19 at 07:51
  • 1
    Thanks, awesome – Wait, how does your hash anchor name work?! It doesn't look at all like the standard given in https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/pdf_open_parameters.pdf – Felix Dombek Jul 17 '19 at 07:54
  • 1
    @FelixDombek Magic :) I use Firefox, and I right click on the navigation panel on the left, and choose "Copy link location", and there you go. – L. F. Jul 17 '19 at 07:57
  • Another little comment: It might be worthwhile to point out that unlike an ofstream, an fstream with in|out will NOT create the file if it doesn't exist (but will instead fail.) So it's not a 1:1 replacement. – Felix Dombek Jul 17 '19 at 08:05
  • @FelixDombek Clarified. – L. F. Jul 17 '19 at 08:08
  • Your answer has solved the problem which has been the actual reason for asking this question (a mixture of `fopen` and `std::ofstream`). Thank you! :-) – Benjamin Bihler Jul 17 '19 at 08:16