How does istream::clear() behave if the stream is actually an ifstream? - c++

I was wondering if calling clear() on an istream is the same / similar to calling close() on an ifstream.
My code looks like this:
void load_content(std::istream &ifs) {
std::string line;
getline(ifs, line);
...
ifs.clear();
}
Before, the argument was a std::ifstream and ifs.close() was called.
But to make it more testable, I changed it do istream such that I can pass filecontents as a stringstream.
Is this safe? In the normal usage of the program, there will always be an iftream passed to the function, only in tests it will be a stringstream.
Do I need to do more than this or is this fine?

Related

Read text file into list without using direct loop using std::list c++

I have a program that reads a list of assignments and removes the "bad" assignments, then writes into a new file. My function that removes the bad assignments works correctly. The code I currently am using to read the text file works correctly also, but is doing so with a while loop. How can I utilize the std::list library to accomplish the same thing without the while loop. Below is the code I am using for the removing of the bad assignmemnts (Prune) along with reading the text file.
void Prune()
{
m_Assignments.remove_if([](const Assignment& assignment){ return !assignment.IsGood();});
}
void Read(std::istream& is)
{
std::string s;
std::getline(is, s);
m_Name = s;
Assignment a;
while (is >> a)
{
m_Assignments.push_back(a);
}
}
You can use std::istream_iterator and std::back_inserter to copy (using std::copy) strings from input stream to the list:
std::copy (
std::istream_iterator<std::string>{is},
std::istream_iterator<std::string>{},
std::back_inserter(a)
);

How do I read from an input file after passing the ifstream object to a function?

as the title suggests, I am having a problem with not being able to read from an input file after passing the ifstream object to a class function. Basically I'm trying to sort a list of numbers using a heap ADT implemented with an array.
int main() {
ifstream infile("input.txt");
HeapSort* heap = new HeapSort(20); // creates a heap (array) with size 20
heap->buildHeap(&infile);
return 0;
}
void HeapSort::buildHeap(ifstream* infile) {
int data;
while (infile >> data) {cout << data << endl;}
infile->close();
}
the error occurs in the conditional of the while loop inside buildHeap. The compiler can't recognize the operator ">>" between an 'int' and an 'ifstream' object. However, strangely enough, if I write that same while loop inside main(), it'll work just fine. Also of note is that if I remove the while loop, the compiler returns no errors. Meaning, simply the act of passing the ifstream object from main to buildHeap is OK.
Please avoid suggesting alternative ways of achieving this. I was asked to not use any special fstream functions like eof(). I can only use the ">>" operator to read from the desired file.
You're passing a pointer to a stream, so you need to dereference it:
while (*infile >> data)
If you want your code to look like what you say you did in main, then you pass a reference:
heap->buildHeap(infile);
//...
void HeapSort::buildHeap(ifstream& infile)
{
int data;
while (infile >> data) { ... }
infile.close();
}

How to write out to a file and make it return the file

int fileReading(string signalFile){
ofstream fileName;
fileName.open(signalFile, ios::in | ios::binary);
//does more stuff here
fileName.close();
return 0;
}
How would I create a new file and switch the return type of the function to a file?
Do I need to create a class for this?
The easiest and probably the most consistent thing to do is to have your function take an fstream as argument (by reference) and then return it,
fstream& fileReading(fstream& strm)
{
// process it here
return strm;
}
This way you are not mixing file names with streams, so your function does only one thing: process a stream. Once you defined your function, you can use it like
fstream fileName("test.txt", ios::in | ios::binary); // we open the stream
fileReading(fileName); // and process the stream, will close automatically at exit from scope
If you try to return a local fstream (i.e. from inside a function), the compiler won't be able to (unless you use C++11), since fstream is non-copyable. In C++11 the compiler will use move semantics and move your local fstream into the returned stream. So in principle this should work:
fstream fileReading(const string& signalFile)
{
fstream fileName;
fileName.open(signalFile, ios::in | ios::binary);
//does more stuff here
// fileName.close(); // do not close it here
return fileName;
}
Then use as
fstream f = fileReading("test.txt");
However, the support for moveable streams seems to be broken in g++4.9 (works in g++5 and clang++). That's why the best is just to pass the stream by reference and return the reference.

How to redirect printing from screen (or any FILE*) into a string/char* in C++

I am working on a C++ code and I wish to do the following:
In the code there is a new type, T, there is a method defined on T that prints some information to a type FILE* variable.
I would like to do some work on this string inside of the program, so I would like to have a variable of type string (or even char*) that will contain what is printed to the screen (if I give the printing function stdout as the File*).
How can I do this ? maybe I can create some FILE* variable and then create (somehow) a string/char* variable with the information that is stored in that File* variable we created ?
Any help is appreciated!
POSIX 1.2008 fmemopen, open_memstream functions create a FILE* pointer which writes to (and/or reads from) memory.
If it does not work for your platform (and there is no other way to hook into FILE *), then you're out of luck.
The next thing I'd try is creating an anonymous pipe, (POSIX pipe, Windows CreatePipe), wrapping its writing side into FILE * (POSIX fdopen, plus Windows _open_osfhandle to get a CRT fd from HANDLE). Here you have to ensure that the pipe's buffer size is enough, or to spawn a thread for reading the pipe. Don't forget to fflush the writing side after the method is done (or use setbuf to disable buffering).
There are several platform-independent ways to do it.
In C++ you can use stringstream(http://www.cplusplus.com/reference/sstream/stringstream/), which has many << operator overloads. So if you pass a reference to ostream& (not oFstream) to the output method, you can easily switch between files, stadard output stream and string outputs, because all this streams are inherited from ostream. Then you can get std::string object from stringstream and get C-string from it if you need.
Code example:
Output function (or method, then you don't need the second argument from the example):
void PrintMyObjectToSomeStream(std::ostream& stream, const MyClass& obj)
{
stream << obj.pubField1;
stream << obj.pubField2;
stream << obj.GetPrivField1();
stream << "string literal";
stream << obj.GetPrivField2();
}
Usage:
MyClass obj1;
std::ofsstream ofs;
std::stringstream sstr;
//...open file for ofs, check if it is opened and so on...
//...use obj1, fill it's member fields with actual information...
PrintMyObjectToSomeStream(obj1,std::cout);//print to console
PrintMyObjectToSomeStream(obj1,sstr);//print to stringstream
PrintMyObjectToSomeStream(obj1,ofs);//print to file
std::string str1=sstr.str();//get std::string from stringstream
char* sptr1=sstr.str().c_str();//get pointer to C-string from stringstream
Or you can overload operator<<:
std::ostream& operator<<(std::ostream& stream, const MyClass& obj)
{
stream << obj1.pubField;
//...and so on
return stream;
}
then you can use it in this way:
MyClass obj2;
int foo=100500;
std::stringstream sstr2;
std::ofstream ofs;//don't forget to open it
//print to stringstream
sstr2 << obj2 << foo << "string lineral followed by int\n";
//here you can get std::string or char* as like as in previous example
//print to file in the same way
ofs << obj2 << foo << "string lineral followed by int\n";
Using FILE is more C than C++ but you can think how to switch between fpirntf and sprintf or use Anton's answer.

declaring input stream

I have a C++ code with
ifstream myfile;
myfile.open("input");
and then has commands like:
myfile.getline(inp,256);
Question: How can I modify myfile.open("input") so that myfile is associated with cin instead of "input"?
I don't want to change all myfile.getline commands to cin.getline.
Declaring myfile=cin does not compile.
Use an istream& reference instead:
std::istream& myfile(std::cin);
Separate it out into a function and take the std::istream& as an argument. Then you can execute on both std::cin and myfile as you wish.
You can put your code into a function that takes a reference to a std::istream, e.g.
void process_data( std::istream & istr )
{ ... }
Then you can call this function both with any std::ifstream and with std::cin:
std::ifstream myfile;
...
process_data( myfile );
process_data( std::cin );
If you insist in using an std::ifstream you can replace the std::streambuf of the base std::istream (std::ifstream overloads rdbuf() so you can't use it directly):
std::ifstream file;
if (use_cin) {
file.std::istream::rdbuf(std::cin.rdbuf());
}