In c++, is stream.clear() necessary after a failure has occurred? - c++

I have the following code:
string promptPlayerForFile(ifstream &infile, string prompt) {
while (true) {
string filename;
cout << prompt;
getline(cin, filename);
infile.open(filename.c_str());
if (!infile.fail()) return filename;
infile.clear();
cout << "Unable to open that file. Try again." << endl;
}
}
The function works as expected: you enter file names until you give a correct one, in which case it associates a stream with the file and returns the filename string.
I then tried commenting out the line infile.clear() to see what happens. (I read that it needs to be included after a failure has occurred in order to reset the relevant bits of the stream.)
However, after commenting this out, the function behaves as before. If I first give a wrong filename and then a correct one it works, so somehow the failure bits get reset even without that line. Is then infile.clear() necessary and what are its appropriate uses?

If you are using C++11 or higher, you don't need to call infile.clear();. If open() is successful, then clear() is called.
If you are using a pre-C++11 compiler, it is necessary to call infile.clear(). The language does not guarantee that the failbit(s) are cleared when open() is successful.
See https://en.cppreference.com/w/cpp/io/basic_ifstream/open for details about the call to clear().

the infile.clear() is relevant if and only if you want to continue to interact with the stream (e.g. read from it). If your program ends anyway, you dont't have to clear the error flags.

Related

Issue with Pointer to an fstream in C++

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!

Implementing File class for both read and write operations on the file

I need to implement a class which holds a regular text file that will be valid for both read and write operations from multiple threads (say, "reader" threads and "writers").
I am working on visual studio 2010 and can use only the available libraries that it (VS 2010) has, so I chose to use the std::fstream class for the file operations and the CreateThread function & CRITICAL_SECTION object from the header.
I might start by saying that I seek, at the beginning, for a simple solution - just so it works....:)
My idea is as follows:
I created a File class that will hold the file and a "mutex" (CRITICAL_SECTION object) as private members.
In addition, this class (File class) provides a "public interface" to the "reader/writer" threads in order to perform a synchronized access to the file for both read and write operations.
See the header file of File class:
class File {
private:
std::fstream iofile;
int size;
CRITICAL_SECTION critical;
public:
File(std::string fileName = " ");
~File();
int getSize();
// the public interface:
void read();
void write(std::string str);
};
Also see the source file:
#include "File.h"
File :: File(std::string fileName)
{
// create & open file for read write and append
// and write the first line of the file
iofile.open(fileName, std::fstream::in | std::fstream::out | std::fstream::app); // **1)**
if(!iofile.is_open()) {
std::cout << "fileName: " << fileName << " failed to open! " << std::endl;
}
// initialize class member variables
this->size = 0;
InitializeCriticalSection(&critical);
}
File :: ~File()
{
DeleteCriticalSection(&critical);
iofile.close(); // **2)**
}
void File :: read()
{
// lock "mutex" and move the file pointer to beginning of file
EnterCriticalSection(&critical);
iofile.seekg(0, std::ios::beg);
// read it line by line
while (iofile)
{
std::string str;
getline(iofile, str);
std::cout << str << std::endl;
}
// unlock mutex
LeaveCriticalSection(&critical);
// move the file pointer back to the beginning of file
iofile.seekg(0, std::ios::beg); // **3)**
}
void File :: write(std::string str)
{
// lock "mutex"
EnterCriticalSection(&critical);
// move the file pointer to the end of file
// and write the string str into the end of the file
iofile.seekg(0, std::ios::end); // **4)**
iofile << str;
// unlock mutex
LeaveCriticalSection(&critical);
}
So my questions are (see the numbers regarding the questions within the code):
1) Do I need to specify anything else for the read and write operations I wish to perform ?
2) Anything else I need to add in the destrutor?
3) What do I need to add here in order that EVERY read operation will occur necessarily from the beginning of the file ?
4) What do I need to modify/add here in order that each write will take place at the end of the file (meaning I wish to append the str string into the end of the file)?
5) Any further comments will be great: another way to implement , pros & cons regarding my implementation, points to watch out , etc'.....
Thanks allot in advance,
Guy.
You must handle exceptions (and errors in general).
No, you destructor even has superfluous things like closing the underlying fstream, which the object takes care of itself in its destructor.
If you always want to start reading at the beginning of the file, just open it for reading and you automatically are at the beginning. Otherwise, you could seek to the beginning and start reading from there.
You already opened the file with ios::app, which causes every write operation to append to the end (including that it ignores seek operations that set the write position, IIRC).
There is a bunch that isn't going to work like you want it to...
Most importantly, you need to define what you need the class to behave like, i.e. what the public interface is. This includes guarantees about the content of the file on disk. For example, after creating an object without passing a filename, what should it write to? Should that really be a file who's name is a single space? Further, what if a thread wants to write two buffers that each contain 100 chars? The only chance to not get interrupted is to first create a buffer combining the data, otherwise it could get interrupted by a different thread. It gets even more complicate concerning the guarantees that your class should fulfill while reading.
Why are you not using references when passing strings? Your tutorial should mention them.
You are invoking the code to enter and leave the critical section at the beginning and end of a function scope. This operation should be bound to the ctor and dtor of a class, check out the RAII idiom in C++.
When you are using a mutex, you should document what it is supposed to protect. In this case, I guess it's the iofile, right? You are accessing it outside the mutex-protected boundaries though...
What is getSize() supposed to do? What would a negative size indicate? In case you want to signal errors with that, that's what exceptions are for! Also, after opening an existing, possibly non-empty file, the size is zero, which sounds weird to me.
read() doesn't return any data, what is it supposed to do?
Using a while-loop to read something always has to have the form "while try-to-read { use data}", yours has the form "while success { try-to-read; use data; }", i.e. it will use data after failing to read it.
Streams have a state, and that state is sticky. Once the failbit is set, it remains set until you explicitly call clear().
BTW: This looks like logging code or a file-backed message queue. Both can be created in a thread-friendly way, but in order to make suggestions, you would have to tell us what you are actually trying to do. This is also what you should put into a comment section on top of your class, so that any reader can understand the intention (and, more important now, so that YOU make up you mind what it's supposed to be).

Reuse a filestream in C++?

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.

Why doesn't closing a file automatically clear error state?

When I use ifstream to read file, I loop over all lines in the file and close it. Then I try opening a different file with the same ifstream object, it still says the End-Of-File error. I'm wondering why closing the file won't automatically clearing the state for me. I have to call clear() explictly after close() then.
Is there any reason why they design it like this? To me, that's really painful if you wanna reuse the fstream object for different files.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void main()
{
ifstream input;
input.open("c:\\input.txt");
string line;
while (!input.eof())
{
getline(input, line);
cout<<line<<endl;
}
// OK, 1 is return here which means End-Of-File
cout<<input.rdstate()<<endl;
// Why this doesn't clear any error/state of the current file, i.e., EOF here?
input.close();
// Now I want to open a new file
input.open("c:\\output.txt");
// But I still get EOF error
cout<<input.rdstate()<<endl;
while (!input.eof())
{
getline(input, line);
cout<<line<<endl;
}
}
Personally, I think close() should reset the flags, as I've been bitten by this in the past. Still, to mount my hobby-horse once more, your read code is wrong:
while (!input.eof())
{
getline(input, line);
cout<<line<<endl;
}
should be:
while (getline(input, line))
{
cout<<line<<endl;
}
To see why, consider what happens if you try to read a completely empty file. The eof() call will return false (because although the file is empty, you have not yet read anything, and only reads set the eof bit) and you will output a line which does not exist.
The call to close may fail. When it does fail, it sets the failbit. If it reset the state of the stream, you wouldn't be able to check whether or not the call to close succeeded.
Because the flags are associated with the stream, not the file.
This has been changed in C++11 (C++0x), not so that close() discards any errors detected but the next open() will call clear() for you.

redirect standard output to a file using multiple thread

I tried to redirect standart output (cout) to a file, for debugging purposes
std::ofstream traceFile;
traceFile.open("c:/path/file.txt");
std::streambuf* fileBuff = traceFile.rdbuf();
std::cout.rdbuf(fileBuff);
std::cout << std::unitbuff;
std::cout << "disk is written\n";
But calling cout from a new thread make the code stuck on a mutex. (xmtx.c 39: _Mtxlock()).
Have you got an idea, how i could solve it?
Thank you
This example works fine for me, whilst your test case doesn't. On my machine your code seemed to double free the streambuf from the file, whereas this example swaps it back before the destructors are called.
May be you need to reset cout's streambuf to original.
std::ofstream traceFile;
traceFile.open("c:/path/file.txt");
std::streambuf* fileBuff = traceFile.rdbuf(), *origBuf;
origBuf = cout.rdbuf(); //Save cout's StreamBuf pointer
std::cout.rdbuf(fileBuff); //Set cout's StreamBuf to file's StreamBuf pointer
std::cout << std::unitbuff;
std::cout << "disk is written\n";
cout.rdbuf(origBuf); //Reset cout's StreamBuf back to original
Also, writing into same file by multiple threads concurrently may not be allowed.
That may be reason for the failure of acquisition of mutex.