I recently wrote some code that I thought was okay, but a colleague says it was causing random crashes in our application. The offending code is writing to an unopened ofstream. My question is: should it be okay to write to an ofstream that has not been opened? This came about when the initialization of a class would not open its ofstream for logging debug information. But subsequent methods would still use the unopened ofstream. Here is an example:
class A {
public:
A(const std::string& fname) {
if (!fname.empty()) {
m_debug_log.open(fname.c_str());
}
}
void DoSomething() {
m_debug_log << "doing something useful now" << std::endl;
}
private:
std::ofstream m_debug_log;
};
My colleague says that he stopped the random crashes by wrapping all output operations to m_debug_log
with a validity check on the ofstream. So the output operations are performed only when m_debug_log
is a valid output stream.
void DoSomething() {
if (m_debug_log)
m_debug_log << "doing something useful now" << std::endl;
}
Of course writing to the stream only when it is valid makes the most sense. But I never expected that writing to the unopened ofstream would cause correctness problems. (Yes, it is inefficient, but coding speed was my highest priority at the time.)
I quickly searched but found nothing definitive about this. In particular I did not see anything explicit about undefined behavior when writing to an uninitialized ofstream. Should the initial implementation have been correct? My question is a general one rather than about a particular implementation. For what it is worth I routinely use VS 2010, VS 2013, Ubuntu 12.04, and Centos 6.3, and found no problems with initial testing. It was only when running for longer periods of time when the crashes occurred.
A default-constructed (unopened) std::ofstream
becomes bad as soon as anything is written to it. Subsequent writes should silently (and safely!) fail.
Unless Microsoft's implementation is peculiar, I suspect the random crashes are coming from elsewhere. Make sure that the m_debug_log
is fully constructed, even if only with the default constructor. Are you sure the real DoSomething
is not a static method?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With