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.
Related
first of all i made a simple class:
class test
{
public:
test(string name="",int age=0);
void getData();
void show();
private:
string name;
int age;
};
test::test(string name,int age)
{
this->age = age;
this->name = name;
}
void test::getData()
{
cin >> age;
cin >> name;
}
void test::show()
{
cout << "AGE:" << age<<"\n";
cout << "NAME:" << name << "\n";
}
in my main function called the getData() method to input values from user and then saved them in a binary file.
Now when i try to read the file, it does store the value in the new object of the class but i get an exception (Exception thrown: read access violation. _Pnext was 0xB414D4.)
my main function looks like this :
int main()
{
ifstream os("new.dat", ios::binary);
test b;
os.read(reinterpret_cast<char*>(&b), sizeof(b));
b.show();
return 0;
}
The issue here is that you are trying to read the test object as if it is a simple flat object. For many, many reasons, this is almost always a bad idea.
In your case, the std::string member is not a simple object at all! Under the hood, std:: string usually has at least 1 pointer member to where it has allocated the string.
If you simply save the stest object in one session, and restore the binary representation in another session, then you set these pointers to addresses that are now completely garbage.
The process of saving a data structure in a way that is later recoverable is called serialisation, and is a complex subject.
The issue here is that you are trying to read the test object as if it is a simple flat object. For many, many reasons, this is almost always a bad idea.
In your case, the std::string member is not a simple object at all! Under the hood, std:: string usually has at least 1 pointer member to where it has allocated the string.
If you simply save the test object in one session, and restore the binary representation in another session, then you set these pointers to addresses that are now completely garbage.
I am trying to reading and write objects to a file in C++, writing the object works fine, reading gives segmentation core dump. I have commented the code for writing objects to file, while writing we can uncomment that part and comment the reading part.
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
class RelianceMart{
string name;
double trolley_number;
public:
RelianceMart(){
name = "NA";
trolley_number = 0;
}
RelianceMart(string name, double trolley_number){
this->name = name;
this->trolley_number = trolley_number;
}
void setname(string name){
this->name = name;
}
string getname(){
return name;
}
void settrolleynumber(double trolley_number){
this->trolley_number = trolley_number;
}
double gettrolleynumber(){
return trolley_number;
}
};
int main(){
string name;
double trl_num;
RelianceMart mart[3];
RelianceMart obj;
// ofstream fout("PersistentStorage.txt");
/*
for(int i=0;i<3;i++){
cin>>name;
cin>>trl_num;
mart[i] = RelianceMart(name, trl_num);
fout.write((char *) & mart[i], sizeof(mart[i]));
}
fout.close();
*/
ifstream fin("PersistentStorage.txt");
while(!fin.eof()){
fin.read((char *) & obj,sizeof(obj));
cout<< obj.getname();
}
fin.close();
return 0;
}
The members of std::string is really nothing more than a member variable for the length, and a member variable being a pointer to the actual string contents.
Pointers are private and unique to a specific process in all modern protected multi-tasking operating systems, no other process (not even one started from the same program) can reuse the same pointer.
When you write the RelianceMart objects, you write the pointer of the name string object to the file. As mentioned above no other process can use this pointer, and therefore can't read the file.
Furthermore when you attempt to read the raw objects, you read raw data overwriting the existing data in the constructed object, and the object won't be properly constructed anymore.
You also don't open the file in binary mode, which is wrong since you write and read raw binary data, not text.
The common solution is to use serialization, and the most common way to do it is simply to overload the "output" and "input" operators << and >>.
In the overloaded functions you simply write and read each object as text, again using the formatted << and >> operators.
Lastly, please read Why is iostream::eof inside a loop condition considered wrong?
I would use a serialization framework, you could use Google's Protocol Buffers(https://developers.google.com/protocol-buffers/).
If you consider a fullblown framework overkill, you can always write your own serialization framework, I've done that, I did use the JSON-format to encode the object.
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();
}
So i written a program where i can input 4 values a first name, last name, height and a signature. I store all values in a Vector but now i would like to learn how i can take the values from my vector and store them in a file and later on read from the file and store back into the vector.
vector<Data> dataVector;
struct Data info;
info.fname = "Testname";
info.lname = "Johnson";
info.signature = "test123";
info.height = 1.80;
dataVector.push_back(info);
Code looks like this i havent found anyway to store objects of a struct into a file so i'm asking the community for some help.
You should provide your struct with a method to write it to a stream:
struct Data
{
// various things
void write_to(ostream& output)
{
output << fname << "\n";
output << lname << "\n";
// and others
}
void read_from(istream& input)
{
input >> info.fname;
input >> info.lname;
// and others
}
};
Or provide two freestanding functions to do the job, like this:
ostream& write(ostream& output, const Data& data)
{
//like above
}
// and also read
Or, better, overload the << and >> operator:
ostream& operator<<(const Data& data)
{
//like above
}
// you also have to overload >>
Or, even better, use an existing library, like Boost, that provides such functionality.
The last option has many pros: you don't have to think how to separate the fields of the struct in the file, how to save more instances in the same file, you have to do less work when refactoring or modifying the struct.
Don't reinvent the wheel: use the Boost serialization libraries.
I'd like to read a file into a struct or class, but after some reading i've gathered that its not a good idea to do something like:
int MyClass::loadFile( const char *filePath ) {
ifstream file ( filePath, ios::in | ios::binary );
file.read ((char*)this, 18);
file.close();
return 0;
}
I'm guessing if i want to write a file from a struct/class this isn't kosher either:
void MyClass::writeFile( string fileName ) {
ofstream file( fileName, ofstream::binary );
file.write((char*)this, 18);
file.close();
}
It sounds like the reason i don't want to do this is because even if the data members of my struct add up to 18 bytes, some of them may be padded with extra bytes in memory. Is there a more correct/elegant way to get a file into a class/struct like this?
The preferred general technique is called serialization.
It is less brittle than a binary representation. But it has the overhead of needing to be interpreted. The standard types work well with serialization and you are encouraged to make your class serialize so that a class containing your class can easily be serialized.
class MyClass {
int x;
float y;
double z;
friend std::ostream& operator<<(std::ostream& s, MyClass const& data);
friend std::istream& operator>>(std::istream& s, MyClass& data);
};
std::ostream& operator<<(std::ostream& s, MyClass const& data)
{
// Something like this
// Be careful with strings (the input>> and output << are not symmetric unlike other types)
return str << data.x << " " << data.y << " " << data.z << " ";
}
// The read should be able to read the version printed using <<
std::istream& operator>>(std::istream& s, MyClass& data)
{
// Something like this
// Be careful with strings.
return str >> data.x >> data.y >> data.z;
}
Usage:
int main()
{
MyClass plop;
std::cout << plop; // write to a file
std::cin >> plop; // read from a file.
std::vector<MyClass> data;
// Read a file with multiple objects into a vector.
std::ifstream loadFrom("plop");
std::copy(std::istream_iterator<MyClass>(loadFrom), std::istream_iterator<MyClass>(),
std::back_inserter(data)
);
// Write a vector of objects to a file.
std::ofstream saveTo("Plip");
std::copy(data.begin(), data.end(), std::ostream_iterator<MyClass>(saveTo));
// Note: The stream iterators (std::istream_iterator) and (std::ostream_iterator)
// are templatized on your type. They use the stream operators (operator>>)
// and (operator<<) to read from the stream.
}
The answer is : there is no silver bullet to this problem.
One way you can eliminate the padding to ensure that the data members in your class is to use(in MSVC which you are using)
#pragma pack( push, 1 )
class YourClass {
// your data members here
int Data1;
char Data2;
// etc...
};
#pragma pack( pop )
The main usefulness of this approach is if your class matches a predefined format such as a bitmap header. If it is a general purpose class to represent a cat, dog, whatever then dont use this approach. Other thing if doing this is to make sure you know the length in bytes of the data types for your compiler, if your code is EVER going to be multi platform then you should use explicit sizes for the members such as __int32 etc.
If this is a general class, then in your save member, each value should be written explicitly. A tip to do this is to create or get from sourceforge or somewhere good code to help do this. Ideally, some code that allows the member to be named, I use something similar to :
SET_WRITE_DOUBLE( L"NameOfThing", DoubleMemberOfClass );
SET_WRITE_INT( L"NameOfThing2", IntMemberOfClass );
// and so on...
I created the code behind these macros, which I am not sharing for now but a clever person can create their own code to save named to stream in an unordered-set. This I have found is the perfect approach because if you add or subtract data members to your class, the save/load is not dependent on the binary representation and order of your save, as your class will doubtless evolve through time if you save sequentially this is a problem you will face.
I hope this helps.