Do I need to manually call close() when I use a std::ifstream?
For example, in the code:
std::string readContentsOfFile(std::string fileName) {
std::ifstream file(fileName.c_str());
if (file.good()) {
std::stringstream buffer;
buffer << file.rdbuf();
file.close();
return buffer.str();
}
throw std::runtime_exception("file not found");
}
Do I need to call file.close() manually? Shouldn't ifstream make use of RAII for closing files?
NO
This is what RAII is for, let the destructor do its job. There is no harm in closing it manually, but it's not the C++ way, it's programming in C with classes.
If you want to close the file before the end of a function you can always use a nested scope.
In the standard (27.8.1.5 Class template basic_ifstream), ifstream is to be implemented with a basic_filebuf member holding the actual file handle. It is held as a member so that when an ifstream object destructs, it also calls the destructor on basic_filebuf. And from the standard (27.8.1.2), that destructor closes the file:
virtual ˜basic_filebuf();
Effects: Destroys an object of class basic_filebuf<charT,traits>. Calls close().
Do you need to close the file?
NO
Should you close the file?
Depends.
Do you care about the possible error conditions that could occur if the file fails to close correctly? Remember that close calls setstate(failbit) if it fails. The destructor will call close() for you automatically because of RAII but will not leave you a way of testing the fail bit as the object no longer exists.
You can allow the destructor to do it's job. But just like any RAII object there may be times that calling close manually can make a difference. For example:
#include <fstream>
using std::ofstream;
int main() {
ofstream ofs("hello.txt");
ofs << "Hello world\n";
return 0;
}
writes file contents. But:
#include <stdlib.h>
#include <fstream>
using std::ofstream;
int main() {
ofstream ofs("hello.txt");
ofs << "Hello world\n";
exit(0);
}
doesn't. These are rare cases where a process suddenly exits. A crashing process could do similar.
No, this is done automatically by the ifstream destructor. The only reason you should call it manually, is because the fstream instance has a big scope, for example if it is a member variable of a long living class instance.
Related
I have an issue with my code below I am trying to use pointer to file stream to write some text in to the file, but the code below does not write in to file, I have tried without pointer to fstream which worked fine, but with pointer I can't see any changes in my text file but the code compile successfully.
fstream *io = new fstream("FILE/myFile.txt" , ios_base::in | ios_base::out);
if(!io -> is_open()){
cout << "Could not open file or file does not exist!" << endl;
exit(1);
}
*io << "Hello World"
Streams buffer the output. If the stream isn't flushed, the output is never written. Since the string written is tiny it will be buffered. The destructor of the stream would flush the stream as would filling the buffer. As written, the pointer is leaked and the stream is never destroyed and, thus, not flushed.
The fix to your problem is in order of preference:
Do not use pointers.
Use a smart pointer, e.g., std::unique_ptr<std::ofstream> to hold the stream.
delete the stream object at the end of the program (this is easy to forget and using automated distruction is much preferable).
At least, close() the stream using io->close(). Not deleteing the stream would be a resource leak.
Flushing the stream using *io << std::flush should still write the buffer. This approach would leak memory as the previous approach but additional also leak a file descriptor.
Personally, would go with approach 1. If I absolute had to use pointers which never happened to me with stream, I would use 2. Everything else would technically work but is likely to result in resource leaks.
You need to close the file :
io->close();
If you don't close the file, it will not flush data on the disk.
When you you fstream object on the stack, when the object goes out of scope, it close the file (in the distructor).
This is probably only a problem of buffer: you need to flush the stream in order to be sure everything is written in the file. The following snippet works fine:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
ofstream* f = new ofstream("out.dat");
if(! f->is_open())
{
cerr << "Impossible to open the file" << endl;
exit(-1);
}
*f << "Hello, world!" << flush;
f->close();
delete f;
return 0;
}
Do not forget that to every new, a delete should follow!
This question already has answers here:
do I need to close a std::fstream? [duplicate]
(3 answers)
Closed 7 years ago.
Below is the code for same case.
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
//myfile.close();
return 0;
}
What will be the difference if I uncomment the myfile.close() line?
There is no difference. The file stream's destructor will close the file.
You can also rely on the constructor to open the file instead of calling open(). Your code can be reduced to this:
#include <fstream>
int main()
{
std::ofstream myfile("example.txt");
myfile << "Writing this to a file.\n";
}
To fortify juanchopanza's answer with some reference from the std::fstream documentation
(destructor)
[virtual](implicitly declared)
destructs the basic_fstream and the associated buffer, closes the file
(virtual public member function)
In this case, nothing will happen and code execution time is very less.
However, if your codes runs for long time when you are continuously opening files and not closing, after a certain time, there may be crash in run time.
when you open a file, the operating system creates an entry to represent that file and store the information about that opened file. So if there are 100 files opened in your OS then there will be 100 entries in OS (somewhere in kernel). These entries are represented by integers like (...100, 101, 102....). This entry number is the file descriptor. So it is just an integer number that uniquely represents an opened file in operating system. If your process open 10 files then your Process table will have 10 entries for file descriptors.
Also, this is why you can run out of file descriptors, if you open lots of files at once. Which will prevent *nix systems from running, since they open descriptors to stuff in /proc all the time.
Similar thing should happen in case of all operating system.
Under normal conditions there is no difference.
BUT under exceptional conditions (with slight change) the call to close can cause an expception.
int main()
{
try
{
ofstream myfile;
myfile.exceptions(std::ios::failbit | std::ios::badbit);
myfile.open("example.txt");
myfile << "Writing this to a file.\n";
// If you call close this could potentially cause an exception
myfile.close();
// On the other hand. If you let the destructor call the close()
// method. Then the destructor will catch and discard (eat) the
// exception.
}
catch(...)
{
// If you call close(). There is a potential to get here.
// If you let the destructor call close then the there is
// no chance of getting here.
}
}
The author presented this code under the title A bus error on my platform
#include <fstream>
#include <iostream>
int main()
{
std::ofstream log("oops.log");
std::cout.rdbuf(log.rdbuf());
std::cout << "Oops!\n";
return 0;
}
The string "Oops!\n" is printed to the file "oops.log". The code doesn't restore cout's streambuf, but VS2010 didn't report a runtime error.
Since log and std::cout share a buffer, that buffer will probably be freed twice (once when log goes out of scope, then once more when the program terminates).
This results in undefined behavior, so it's hard to tell the exact reason why it triggers a bus error on his machine but silently fails on yours.
Since the other answers don't mention what to do about this I'll provide that here. You need to save and restore the buffer that cout is supposed to be managing. For example:
#include <fstream>
#include <iostream>
// RAII method of restoring a buffer
struct buffer_restorer {
std::ios &m_s;
std::streambuf *m_buf;
buffer_restorer(std::ios &s, std::streambuf *buf) : m_s(s), m_buf(buf) {}
~buffer_restorer() { m_s.rdbuf(m_buf); }
};
int main()
{
std::ofstream log("oops.log");
buffer_restorer r(std::cout, std::cout.rdbuf(log.rdbuf()));
std::cout << "Oops!\n";
return 0;
}
Now when cout's buffer is replaced before cout is destroyed at the end of the program, so when cout destroys its buffer the correct thing happens.
For simply redirecting standard io generally the environment already has the ability to do that for you (e.g., io redirection in the shell). Rather than the above code I'd probably simply run the program as:
yourprogram > oops.log
Also one thing to remember is that std::cout is a global variable with all the same downsides as other global variables. Instead of modifying it or even using it you may prefer to use the usual techniques to avoid global variables all together. For example you might pass a std::ostream &log_output parameter around and use that instead of having code use cout directly.
Your program has Undefined Behavior.
The destructor of the global cout object will delete the stream buffer when going out of scope, and the same is true of log, which also owns that very same stream buffer. Thus, you are deleting the same object twice.
When a program has Undefined Behavior, anything could happen, from formatting your hard drive to terminating without any error.
On my platform, for instance, the program enters an infinite loop after returning from main().
I have a program that takes multiple files as input. What I'm trying to do is use the same filestream? I keep getting an error when trying to open the stream with the second file. Why is not code not valid and creating an error at compile time? argv[2] is a const char*.
error: no match for call to '(std::ifstream) (char*&)'
ifstream fin(argv[1]);
//work with filestream
fin.close();
fin(argv[2]);
//work with filestream
fin.close();
The first line ifstream fin(argv[1]); is evoking ifstream's constructor, and the constructor can only be called once per object. Your code is trying to call it a second time. Try using open() instead:
fin.open(argv[2]);
As an aside, you may also want to call clear() before you reopen your ifstream. The reason for this is that if the first open() (or even close()) fails, error bits on the ifstream will be set, and won't be cleared by close().
Use a local scope:
{
ifstream fin(argv[1]);
//work with filestream
}
{
ifstream fin(argv[2]);
//work with filestream
}
Note that you dont manually need to close the streams, this is handled automatically when they go out of scope.
I have ifstream and an ofstream that in runtime might be opened or not (depends on what the user enters in command line. i declare the variables anyway, and i have a method that opens the stream if needed.
my problem is at the end of the program i don't know if i need to close them or not.
Is there anyway in c++ to know if a stream was opened? Like in Java you can give a stream the null value and then ask if its null (it means that it was never opened)..
Is it ok to close a stream that was never opened?
this is the code:
int main(int argc, char* argv[]) {
static std::ifstream ifs;
static std::ofstream ofs;
//might or might not open the streams:
OpenStreams(ifs,ofs,argc-1,argv);
........
//here i would like to close the streams at the end of the program
//or not (if they were not opened
return 0;
}
Thanks!
I don't really know, nor care to look. Just leave it to the destructors, the standard file streams will close the files during destruction if needed.
EDIT: On lifetimes of objects and guaranteed destruction...
To follow up the second comment to Ben Voigt that I wrote, this is a small test on object lifetimes:
#include <cstdlib>
#include <iostream>
#include <string>
struct test {
std::string name;
test( std::string const & name ) : name(name) {
std::cout << "test " << name << std::endl;
}
~test() { std::cout << "~test " << name << std::endl; }
};
void foo( bool exit ) {
test t1( "1" );
static test t2( "2" );
test t3( "3" );
if ( exit ) {
std::exit(1);
}
}
int main()
{
foo(false);
std::cout << std::endl;
foo(true);
}
And the result of the execution:
test 1
test 2
test 3
~test 3
~test 1
test 1
test 3
~test 2
It can be seen that during the first execution the construction of the objects in foo occurs in the same order as the code., but when the function exits only the objects with auto storage get destroyed, with the object with static storage outliving the function execution.
In the second call to foo, the auto objects get recreated, while the static object doesn't, as expected, since it was created in a previous call. Because foo calls exit() in the second call, the auto objects in foo don't get destructed. On the other hand, the static object is correctly destructed.
Why not just test this using is_open() before you issue the close()?
No close call needed - the streams close itself when they are open when they are destroyed. Also, the static there looks suspicious. main is called only once, so it doesn't have any effect here (apart from pedantic standardese differences that don't matter here, i think.... Definitely not in the case shown).
That said, you can just call close if a stream is not opened - close will return a null pointer if it wasn't open. (I was looking at the spec for basic_filebuf<>::close - the file streams's close returns void).
File-streams can also handle non-open streams: If the stream wasn't open, it sets the failbit. You can check for that using fail() (which tests whehter the failbit or badbit is set). But there is is_open anyway to test whether the stream is open, but you don't need it for the above reasons.
Just don't make the variables static, that way they automatically close when main() returns.
You can use the is_open method to test if a stream has been opened, then close it.
Why not set a flag before opening a stream. Check the flag again if you need to close the stream object if any.
Better would be to pass that open stream object to the flag while opening a stream & use it to close the stream. If the flag has not been initialized or is null don't close.