problem passing in istream argument to a class constructor - c++

I have the following code in my header file:
class Factovisors {
public:
Factovisors(std::istream& strm):strm_(strm)
{
}
void run()
{
unsigned int n,m;
while (!strm_.eof()) {
strm_ >> n >> m;
if (isFact(n,m))
std::cout << m << " divides " << n << "!\n";
}
}
std::istream strm_;
};
My .cpp file has the following code.
std::ifstream strm("factovisor.test");
Factovisors facto(strm);
facto.run();
strm.close();
The error my compiler gives me is:
std::ios::basic_ios(const std::ios &) is not accessible from
std::istream::basic_istream(const std::istream &)
I imagine I am missing something really obvious. So any help would be greatly appreciated.

The problem is that istream is an "interface". It has pure virtual functions, so it doesn't make sense to have a copy of it. What you might do is to keep a reference to the passed stream:
std::istream& strm_;
strm_ could be ifstream or istringstream or any input stream derived from istream.

You can't copy-construct a stream because the base-class ios has its copy ctor private. Try making the stream member a reference, rather than a standalone object.

You are trying to store a copy of the stream. This will not work, since streams are not copyable. Best you can do is store a reference or a pointer.
However, if only one method is going to use the stream, just pass a reference to this method.
Other problems:
while (!strm_.eof()) {
strm_ >> n >> m;
if (isFact(n,m))
Eof is set when an attempt to read data fails because of this. As it is you are bound to read the last entry twice. Instead:
while (strm >> n >> m )
if (isFact(n, m)

Related

Problems while opening a .dat file in c++

so basically I was trying to save a class inside a .dat file but in my code but it says this error No matching member function for call to 'open' but I put fstream header. I don't know if I'm writing something wrong. I use Xcode 10.
class memberinformation
{
string name; //name
long int phonenumber; // phone number
int memberid; // member id
public :
memberinformation()
{ name="not assigned" ;
phonenumber=0;
memberid=0;
}
int option3();
int option2();
int option1();
int option4();
};
void wrt_file() //file function
{
memberinformation k;
fstream f;
f.open ("information.dat",ios::app,ios::binary) //this is where I get the error.
f.write((char*)&k,sizeof(k));
}
You are lucky to have been stopped by a simple error. #Alex44 has already shown how to get rid of the error:
f.open ("information.dat",ios::app|ios::binary); //this is where I get the error.
But the following line is even worse:
f.write((char*)&k,sizeof(k));
because the compiler will not show any error, while the content of the string will not be saved in the file. std::string is not trivially copiable and because of that, the memberinformation class is not either. So you should not try to write it to a file as raw bytes.
You should instead write a serialization function that writes to a binary stream (just a possible serialization way):
phonenumber as a long int (no problem there)
memberid as an int (no problem there)
name.size as a size_t
name.data as name.size bytes
The other two answers have answered:
Why its not compiling.
Why its a bad idea to write binary objects.
I would suggest that you serialize the object via the standard C++ technique of using the stream operators. This makes writting/reading the objects trivial and usually makes debugging problems easy.
Using the format suggested by #serge-ballesta in his post:
class memberinformation
{
string name; //name
long int phonenumber; // phone number
int memberid; // member id
public :
// OLD STUFF GOES HERE
void swap(memberinformation& other) noexcept
{
using std::swap;
swap(name, other.name);
swap(phonenumber, other.phonenumber);
swap(memberid, other.memberid);
}
friend std::ostream& operator<<(std::ostream& str, memberinformation const& data)
{
return str << data.phonenumber << " "
<< data.memberid << " "
<< data.name.size() << " "
<< data.name << " ";
}
friend std::istream& operator<<(std::istream& str, memberinformation& data)
{
memberinformation tmp;
std::size_t nameSize
if (str >> tmp.phonenumber >> tmp.memberid >> nameSize) {
// All sizes were read correctly.
tmp.name.resize(nameSize);
if (str.ignore(1).read(&tmp.name[0], nameSize)) {
// ignored the space and read the name correctly.
// So now we update the "data" object
tmp.swap(data);
}
}
return str;
}
};
Now in your code:
int main()
{
memberinformation object;
std::cout << object;
std::cin >> object;
std::ofstream file("Data.dat");
file << object;
}
You miss a semicolon and you need to "bitwise or" your flags:
void wrt_file() //file function
{
memberinformation k;
fstream f;
f.open ("information.dat",ios::app|ios::binary); //this is where I get the error.
...
}
The answers above address your initial problem. I'm going to talk about two more.
First, you probably should f.close() at the end of your method. It may be perfectly fine to let it drop out of scope and clean up from there, but I personally think that's ugly, and I wouldn't count on it.
Second, I wouldn't store the data in binary unless there's a really good reason to do it. It won't be portable. Serge above suggests a serialization method. I'd consider an alternate approach. I'd write to the file in a human readable form such as JSON. Yes, it's a little more work, but...
-If you change your class, your old files will still be readable
-They are portable across environments
-You can actually look at them and readily understand what they contain
So Serge's suggestions above aren't horrible, but I'd pick a more modern serialization / deserialization style.
Note that your f.write won't work because your object contains other objects, you don't know how they work under the hood. That string, for instance, almost certainly can't be dumped the way you're trying to do it. Plus you aren't only dumping your data.
Also, you should printf the sizeof(k). You might find it interesting information. Try to account for every byte. You could printf the sizeof(k.name) to help you work some of it out.
I'm almost positive the information doing so would surprise you, but I haven't actually done it myself, because I would never try to raw memory copy C++ objects, and that's in effect what you're trying to do.

How to assign istringstream and ifstream to an istream variable?

I want to have a variable of type istream which can hold either the contents of a file or a string. The idea is that if no file was specified, the variable of type istream would be assigned with a string.
std::ifstream file(this->_path)
and
std::istringstream iss(stringSomething);
to
std::istream is
I've tried just assigning them to the istream variable like I would with other objects that inherit from the same base class, but that didn't work.
How to assign istringstream and ifstream to an istream variable?
Base class pointers can point to derived class data. std::istringstream and std::ifstream both derived from std::istream, so we can do:
//Note that std::unique_ptr is better that raw pointers
std::unique_ptr<std::istream> stream;
//stream holds a file stream
stream = std::make_unique<std::ifstream>(std::ifstream{ this->_path });
//stream holds a string
stream = std::make_unique<std::istringstream>(std::istringstream{});
Now you just have to extract the content using
std::string s;
(*stream) >> s;
You can't assign to a std::istream but you can bind to a reference like this:
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
std::istringstream test_data(R"~(
some test data here
instead of in an external
file.
)~");
int main(int, char* argv[])
{
// if we have a parameter use it
std::string filename = argv[1] ? argv[1] : "";
std::ifstream ifs;
// try to open a file if we have a filename
if(!filename.empty())
ifs.open(filename);
// This will ONLY fail if we tried to open a file
// because the filename was not empty
if(!ifs)
{
std::cerr << "Error opening file: " << filename << '\n';
return EXIT_FAILURE;
}
// if we have an open file bind to it else bind to test_data
std::istream& is = ifs.is_open() ? static_cast<std::istream&>(ifs) : test_data;
// use is here
for(std::string word; is >> word;)
{
std::reverse(word.begin(), word.end());
std::cout << word << '\n';
}
}
Take a page out of the standard library: don't assign a value; assign a reference. That's probably what you want anyway.
std::istringstream iss(stringSomething);
std::istream& input(iss);
Because streams carry a lot of state, copying them is fraught with semantic questions. Consider for example what tellg should report in the copy after the original calls seekg. References by contrast answer the question transparently.
In C++, you cannot assign an object of type Child to a variable of type Parent, even if Child inherits from Parent. You can assign a pointer of type Child to a pointer of type Parent, however. You may want to consider dynamically allocating the objects.
In C++
std::istream is;
is an actual object, assigning to it will invoke the copy assignment operator which will copy the subobject of iss which is a std::istream into is and slice it. The example linked by LogicStuff will show that you need to assign a reference or pointer to iss like so:
std::istream &is_ref = iss;
The difference between values, references and pointers is fundamental to C++, I would advise getting a strong grasp of them.
std::istream can be constructed from a std::streambuf (basically the device that produces or consumes characters). All i/ostream objects have an associated std::streambuf and can be shared.
std::ifstream file(this->_path);
std::istringstream iss("str in gSo met hing");
std::istream A(iss.rdbuf()); // shares the same buffer device with iss
std::string str;
//////////////
while(A >> str) std::cout << str << " | "; //read everything from stream (~> iss)
std::cout << std::endl;
A = std::move(file);
while(A >> str) std::cout << str << " | "; //read from file, using same stream (~> file)

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();
}

Can an istream variable be a class variable

While developing a program in C++ using VS2010 , can I define
std::istream streamRead(ReadBuf&); // struct ReadBuf : public std::streambuf declared before
and use this streamRead in multiple functions in my program?
If not, can anyone suggest me how to read a stream using getline. I have to read the same stream from different functions.
Thank you in advance.
EDIT:
The struct declared in my header file is as below:
struct ReadBuf : public std::streambuf
{
ReadBuf(PBYTE s,size_t n)
{
setg((char*)s,(char*) s,( char*)s + n);
}
};
I have a buffer in memory and the input to my program is its pointer and size. Using the above structure, I copy it to a streambuffer. Now I have to read this streambuffer line by line. This is my requirement.
For example some of my functions are:
int GetSessionN(int session_id,SessionDetail &N_session);
int GetInstanceId(string header,SessionDetail &N_session);
int GetDriverDetails(string body_data,SessionDetail &N_session);
I have to read the first n lines from the stream using GetSessionN and then the successive n lines in the next function and so on.
This is where I initialise the object of ReadBuf. I am not able to initialize it globally.
int SetupLogReader::ProcessLogFile(PBYTE &mem_ptr, ULONG &size)
{
string read;
ReadBuf buf(mem_ptr, size);
istream streamRead(&buf);// Not able use StreamRead declared in header here.
}
you should not copy the stream when returning it in the function but reference it, i.e:
std::istream &streamRead(ReadBuf&){
if (_stream == null){
// create stream
_stream = [newly created stream];
}
return _stream;
}
Edit:
You could also use std::istringstream as it already provides the functionality you are looking for:
from istringstream manual:
std::string stringvalues = "line1\nline2";
std::istringstream iss (stringvalues);
for (int n=0; n<2; n++)
{
char val[256];
iss.getline(val, 256);
std::cout << val << '\n';
}

How to write and use C++ method to write/read from any stream?

I must write class with one method to read data from any stream (cin, ifstream, etc...) and second to write to any stream. I need something like:
void save(std::ostream &stream);
but no idea how to impement and use it.
Thanks for help.
Before you implement anything, you should determine the structure, layout or protocol to use for storing and loading data members from a file.
Here's a example:
struct MyClass
{
void load_from_stream(std::istream& inp)
{
inp >> first_value;
inp >> second_value;
}
unsigned int first_value;
double second_value;
};
The method will accept any object derived from std::istream, such as std::cin or std::ifstream.
Usage:
MyClass m;
m.load_from_stream(cin);
Similarly, for the std::ostream and saving.