0

I am writing a config for my program. This config is stored in json format using nlohman json. I am using std::fstream to write json object to file. All was fine, but after some moment my program stopped writing to file.
Here is a minimal reproducible example:

#include <iostream>

#include <nlohmann/json.hpp>
#include <fstream>
#include <iomanip>

bool load(std::fstream &config_fs) {
    if (config_fs) {
        try {
            nlohmann::json json;
            config_fs >> json;
            std::cout << json << std::endl;
            return true;
        } catch (std::exception &e) {
            std::cout << "54 " << (bool)config_fs << std::endl; // 1
            std::cout << "Cannot load config: " << e.what() << std::endl;
            return false;
        }
    }
    std::cout << "Cannot load config because file is not open" << std::endl;
    return false;
}

bool save(std::fstream &config_fs) {
    std::cout <<  "37 " << (bool)config_fs << std::endl;
    if (config_fs) {
        nlohmann::json json{{"test", 42}};
        std::cout <<  "39 " << (bool)config_fs << " " << config_fs.is_open() << " " << strerror(errno) << std::endl;
        config_fs << std::setw(4) << json << std::endl;
        std::cout <<  "41 " << (bool)config_fs << " " << config_fs.is_open() << " " << strerror(errno) << std::endl;
        return true;
    }
    std::cout << "Cannot save config because file is not open" << std::endl;
    return false;
}

int main() {
    std::string config_file = "../config_test.json";
    std::fstream config_fs(config_file, std::ios::in | std::ios::out);
    if (!config_fs) {
        std::cout << "Cannot open configuration file " << config_file <<  ", creating it" << std::endl;
        config_fs.open(config_file, std::ios::out);
        if (!config_fs) {
            std::cout << "Cannot create config file " << config_file << std::endl;
        } else {
            config_fs.close();
            config_fs.open(config_file, std::ios::in | std::ios::out);
        }
    }
    if(!load(config_fs)) {
        std::cout << "Cannot load config from " << config_file << ", putting default values" << std::endl;
        std::cout << "21 " << (bool)config_fs << std::endl;
        save(config_fs);
    }

    return 0;
}

And here is output of the programm:

54 1
Cannot load config: [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal
Cannot load config from ../config_test.json, putting default values
21 1
37 1
39 1 1 Success
41 0 1 Success

It means that fstream closes after my write attempt with Success errno and file stays empty! I do not know what may cause such a behavior. I also could not find any similar questions and i really confused about that.
Please point me, what can be reason for this problem.
Thank you!

UPD: Exception 'std::ios_base::failure[abi:cxx11]' what(): basic_ios::clear: iostream error was thrown in output_stream_adapter::write_characters(const CharType* s, std::size_t length) after enabling exceptions for fstream with config_fs.exceptions(std::ios::badbit | std::ios::failbit);

  • 1
    1) Why are you certain, that the file fstream closed itself? I see nothing, in information presented, that would guide me to such conclusion. Did you try stepping through your code with a debugger, to verify that? 2) Please provide [mre]. – Algirdas Preidžius Feb 18 '20 at 12:30
  • @AlgirdasPreidžius, i am certain because i\`ve logged ifstream\`s state before `config_fs << std::setw(4) << json << std::endl;` and after. And before that call stream was opened, and after that it was closed without errors. I tried to look inside json '<<' operator and there was nothing that could close fstream. – Prostoi Chelovek Feb 18 '20 at 15:09
  • 1) "_i am certain because i`ve logged ifstream`s state before config_fs << std::setw(4) << json << std::endl; and after._" Where is such check? You logged it before `serialize`, but not before the `operator<<` invocation. If you had stepped through your code with a debugger, you wouldn't need to rely on arbitrary logging output, in the first place (which doesn't capture call-stack information). 2) I will repeat myself: **please provide [mre]**. – Algirdas Preidžius Feb 18 '20 at 18:15
  • @AlgirdasPreidžius, i was surprised that i could reproduce that problem, but [here is it](https://pastebin.com/TMzk5NY4). It gives the same result as my snippet above. I also can`t step through with debugger because it doesn\`t show state of the fstream. – Prostoi Chelovek Feb 19 '20 at 06:02
  • 1) The [mre] should be present in the question itself, and not hidden behind links. What does `operator<<` overloaded for `ostream`, and `nlohmann::json` do, most likely defined in the library you are using, do? 2) You never, actually, test if the file is open. `std::ofstream::operator bool ()` returns whether the stream has no errors, not whether the file is open. – Algirdas Preidžius Feb 19 '20 at 11:14
  • @AlgirdasPreidžius, i have updated the question with minimal example that also prints `.is_open()` result. Turns out, that fstream wasn\`t closed, but had some errors. I figured out, that it is possible to enable exceptions for fstream. Exception was thrown on [this line](https://github.com/nlohmann/json/blob/973c52dd4a9e92ede5ca4afe8b3d01ef677dc57f/single_include/nlohmann/json.hpp#L11250) in `write` function: `std::ios_base::failure[abi:cxx11] what(): basic_ios::clear: iostream error` – Prostoi Chelovek Feb 19 '20 at 16:06

0 Answers0