C++でテキストファイルに上書きしていく方法


C++で以下のようにwhileループを回しながら、テキストファイルに上書きをしていきたいです。  
下記のコードだと "text" という文字が "texttexttext" と追記されていってしまいます。上書きをするにはどうしたら良いですか？

[code]

    #define TEMP_FILE_NAME  "\\tmp.txt"
    std::ofstream ofs;
    
    SHGetFolderPath(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, TmpPath); 
    PathAppend(TmpPath, _T(TEMP_FILE_NAME));
    
    remove(TmpPath);
    ofs.open(TmpPath,std::ios::trunc);
    
    while(true)
    {
        ofs << "test";
    }
    
[/code]




C++言語ではコンストラクタ・デストラクタが用意されており、[RAII](https://ja.wikipedia.org/wiki/RAII)が実現されています。

質問のように

>
[code]

>     std::ofstream ofs;
>  
[/code]

と実際の変数利用タイミングと全く異なる位置に変数定義してしまうと、コンストラクタ・デストラクタが期待されるタイミングで動作しません。

[code]

    for (;;) {
        std::ofstream ofs;
        ofs.open(TmpPath,std::ios::trunc);
        ofs << "test";
    }
    
[/code]

と変数利用個所で定義されていれば、ループ毎に`ofs`はコンストラクタ・デストラクタが動作し、毎回ファイルへの書き出し・クローズ処理が行われるようになります。

その上でこのように使われることを想定し、`std::ofstream`コンストラクタは`open()`を自動的に呼ぶ機能も備えられており、

[code]

    for (;;) {
        std::ofstream ofs{ TmpPath, std::ios::trunc };
        ofs << "test";
    }
    
[/code]

とできます。この場合、`std::ofstream ofs{ TmpPath, std::ios::trunc }`
の行でファイルオープンが行われ、ループ末尾の `}` でバッファフラッシュとファイルクローズが行われます。

もし仮に`test`のみを書き込みたいのであれば、変数を付けずに

[code]

    for (;;) {
        std::ofstream{ TmpPath, std::ios::trunc } << "test";
    }
    
[/code]

と書くことができます。この場合、この1行だけで、ファイルオープン・バッファフラッシュ・ファイルクローズが行われますので、ループ内に他の処理があってもファイル操作のタイミングが明確になります。

* * *

>
[code]

>     PathAppend(TmpPath, _T(TEMP_FILE_NAME));
>     remove(TmpPath);
>  
[/code]

C++17から[`<filesystem>`](https://cpprefjp.github.io/reference/filesystem.html)が提供されており、こういったパス操作・ファイル操作が可能になっています。

[code]

    #include <filesystem>
    ...
    auto const path = std::filesystem::path{ TmpPath } / TEMP_FILE_NAME;
    std::filesystem::remove(path);
    for (;;) {
        std::ofstream ofs{ path, std::ios::trunc };
        ofs << "test";
    }
    
[/code]

* * *

akira ejiriさんのこの回答は非常に危険な行為であり、推奨できません。

> ofstreamはファイルディスクリプタをメンバに持っているのですが、publicではなく、継承しないと見えません(でした)。
[code]

>     struct tmpfilebuf : public std::basic_filebuf<std::ofstream::char_type>
> {
>         tmpfilebuf(std::basic_filebuf<std::ofstream::char_type> &&other)
>             : std::basic_filebuf<std::ofstream::char_type>(std::move(other))
>         {
>         }
>         int fd() { return this->_M_file.fd(); }
>     };
>  
[/code]

[識別子](https://ja.cppreference.com/w/cpp/language/identifiers)に

>   * キーワードである識別子は、それ以外の目的に使用することはできません。
>   * いずれかの場所に二重のアンダースコアを持つ識別子は予約されています。
>   * アンダースコアで始まりその直後に大文字が続く識別子は予約されています。
>   * アンダースコアで始まる識別子はグローバル名前空間では予約されています。
>

とあるように `_M_file` は予約語であり、この場合、GCC付属のlibstdc++が独自に使用しているものです。いくつかの実装を調べました。

  * [GCC libstdc++-v3の`fstream`](https://github.com/gcc-mirror/gcc/blob/releases/gcc-12.2.0/libstdc++-v3/include/std/fstream#L84-L123)  
[GCC 3.3.0で登場](https://github.com/gcc-
mirror/gcc/commit/d3a193e36cdf55fbff3bd0f244bc36bc09871ee1#diff-78f7933954d13f1dde6d4132bf108dfc91c2e82b0665ccd94fdffc57ada6f755)して以降20年ほど変更ない

  * [LLVM libc++の`fstream`](https://github.com/llvm/llvm-project/blob/llvmorg-15.0.0/libcxx/include/fstream#L214-L293)  
`FILE* __file_;`はあるが`private`でありpublic継承しても参照できない

  * [Microsoft STLの`fstream`](https://github.com/microsoft/STL/blob/main/stl/inc/fstream#L164-L799)  
`FILE* _Myfile;`はあるが`private`でありpublic継承しても参照できない

となっていて、GCCにのみ通用する特殊な技です。




C++言語ではコンストラクタ・デストラクタが用意されており、[RAII](https://ja.wikipedia.org/wiki/RAII)が実現されています。

質問のように

>
[code]

>     std::ofstream ofs;
>  
[/code]

と実際の変数利用タイミングと全く異なる位置に変数定義してしまうと、コンストラクタ・デストラクタが期待されるタイミングで動作しません。

[code]

    for (;;) {
        std::ofstream ofs;
        ofs.open(TmpPath,std::ios::trunc);
        ofs << "test";
    }
    
[/code]

と変数利用個所で定義されていれば、ループ毎に`ofs`はコンストラクタ・デストラクタが動作し、毎回ファイルへの書き出し・クローズ処理が行われるようになります。

その上でこのように使われることを想定し、`std::ofstream`コンストラクタは`open()`を自動的に呼ぶ機能も備えられており、

[code]

    for (;;) {
        std::ofstream ofs{ TmpPath, std::ios::trunc };
        ofs << "test";
    }
    
[/code]

とできます。この場合、`std::ofstream ofs{ TmpPath, std::ios::trunc }`
の行でファイルオープンが行われ、ループ末尾の `}` でバッファフラッシュとファイルクローズが行われます。

もし仮に`test`のみを書き込みたいのであれば、変数を付けずに

[code]

    for (;;) {
        std::ofstream{ TmpPath, std::ios::trunc } << "test";
    }
    
[/code]

と書くことができます。この場合、この1行だけで、ファイルオープン・バッファフラッシュ・ファイルクローズが行われますので、ループ内に他の処理があってもファイル操作のタイミングが明確になります。

* * *

>
[code]

>     PathAppend(TmpPath, _T(TEMP_FILE_NAME));
>     remove(TmpPath);
>  
[/code]

C++17から[`<filesystem>`](https://cpprefjp.github.io/reference/filesystem.html)が提供されており、こういったパス操作・ファイル操作が可能になっています。

[code]

    #include <filesystem>
    ...
    auto const path = std::filesystem::path{ TmpPath } / TEMP_FILE_NAME;
    std::filesystem::remove(path);
    for (;;) {
        std::ofstream ofs{ path, std::ios::trunc };
        ofs << "test";
    }
    
[/code]

* * *

akira ejiriさんのこの回答は非常に危険な行為であり、推奨できません。

> ofstreamはファイルディスクリプタをメンバに持っているのですが、publicではなく、継承しないと見えません(でした)。
[code]

>     struct tmpfilebuf : public std::basic_filebuf<std::ofstream::char_type>
> {
>         tmpfilebuf(std::basic_filebuf<std::ofstream::char_type> &&other)
>             : std::basic_filebuf<std::ofstream::char_type>(std::move(other))
>         {
>         }
>         int fd() { return this->_M_file.fd(); }
>     };
>  
[/code]

[識別子](https://ja.cppreference.com/w/cpp/language/identifiers)に

>   * キーワードである識別子は、それ以外の目的に使用することはできません。
>   * いずれかの場所に二重のアンダースコアを持つ識別子は予約されています。
>   * アンダースコアで始まりその直後に大文字が続く識別子は予約されています。
>   * アンダースコアで始まる識別子はグローバル名前空間では予約されています。
>

とあるように `_M_file` は予約語であり、この場合、GCC付属のlibstdc++が独自に使用しているものです。いくつかの実装を調べました。

  * [GCC libstdc++-v3の`fstream`](https://github.com/gcc-mirror/gcc/blob/releases/gcc-12.2.0/libstdc++-v3/include/std/fstream#L84-L123)  
[GCC 3.3.0で登場](https://github.com/gcc-
mirror/gcc/commit/d3a193e36cdf55fbff3bd0f244bc36bc09871ee1#diff-78f7933954d13f1dde6d4132bf108dfc91c2e82b0665ccd94fdffc57ada6f755)して以降20年ほど変更ない

  * [LLVM libc++の`fstream`](https://github.com/llvm/llvm-project/blob/llvmorg-15.0.0/libcxx/include/fstream#L214-L293)  
`FILE* __file_;`はあるが`private`でありpublic継承しても参照できない

  * [Microsoft STLの`fstream`](https://github.com/microsoft/STL/blob/main/stl/inc/fstream#L164-L799)  
`FILE* _Myfile;`はあるが`private`でありpublic継承しても参照できない

となっていて、GCCにのみ通用する特殊な技です。

