Reputation: 93
I have a class AccountManagement in AccountManagement.cpp. I have another class called Account in Account.cpp. I have a template that Orders the given data inside the list using OrdereList class, which also has it's own iterator. The AccountManagement class outputs the Accounts list in a binary file as shown below:
void AccountManagement::saveData(const char * file) //saves data in the specified binary file
{
ofstream out(file, ios::out | ios::binary);
if(!out)
{
cerr<<"Problem opening output file!"<<endl;
}
OrderedList<Account>::iterator it = this->account_manager.begin();
for(int i = 0; i < this->total_accounts; i++)
{
Account temp = *it;
out.write((char*)&temp, sizeof(Account));
it++;
}
out.close();
}
I have defined a following function inside AccountManagement class that reads all the data from binary file and outputs it. This function works perfectly fine. It is shown here:
void AccountManagement::output()
{
ifstream in("accounts.dat", ios::in | ios::binary);
if(!in)
{
cerr<<"File doesn't exist!"<<endl;
exit(1);
}
Account acc;
while(in.read((char*)&acc, sizeof(Account)))
{
cout<<acc;
}
in.close();
}
However, when I use this same function (with different name) in another file, which has Account.h header file as well to retrieve data from the same "account.dat" file it gives me segmentation fault. What could be the problem? Following is the function:
void loadData()
{
ifstream in("accounts.dat", ios::in | ios::binary);
if(!in)
{
cerr<<"File doesn't exist!"<<endl;
exit(1);
}
Account acc;
while(in.read((char*)&acc, sizeof(Account)))
{
cout<<acc;
}
in.close();
}
Account's class declaration:
class Account
{
friend ostream& operator<<(ostream&,const Account&); //overloading << operator
friend istream& operator>>(istream&,Account&); //overloading >> operator
public:
void operator=(const Account&); //overloading = operator
bool operator<=(const Account&); //overloading <= operator
bool operator<(const Account&); //overloading < operator
private:
string number; //Account Number
char name[100]; //Account holder's name
char sex; //M or F indicating the gender of account holder
MYLIB::Date dob; //date of birth of account holder
char address[100]; //address of account holder
char balance[20]; //balance of account holder
};
Upvotes: 0
Views: 132
Reputation: 73587
Your function AccountManagement::output()
gives the impression it works perfectly, if you save the object and load it again in the same object and provided the string hasn't changed in the meantime.
What's wrong ?
As soon as your object is no longer a POD object (i.e. it contains data that use pointers, or use virtual functions, etc...), you can't just save it just by writing its memory to the disk.
In your case, the second function fails for this reason. The first function only gives the impression that it works. The string is a complex object that stores somewhere pointers to dynamically allocated memory. If you write the object and read it back as you did, without changing the object, the values that are in memory are simply re-read. The value of the hidden pointer that is read is exactly what it was before the read. That's a very lucky situation. But in most cases it will fail.
How to solve it ?
To save your object, you should serialize it: write/reade each component to the file separatly, using an appropriate function.
THe easiest way to do this is to use some existing serialisation libraries, such as boost serialization.
Upvotes: 0
Reputation: 409442
I don't know about the MYLIB::Date
class, but it's enough that you have a std::string
object in there.
The std::string
object allocates memory dynamically to fit the string it contains. And memory allocated on the heap is available only to the current process, you can't save a pointer (which is inside the std::string
class) and load it from some other process and hope there will be valid memory at that pointer.
If you save a pointer to dynamically allocated memory in one process, and load and use it from another process then you will have undefined behavior.
You need to serialize the string in order to save it. Possible the MYLIB::Data
object as well.
Disclaimer: It will work on small embedded systems with a single unified address map, unfortunately all the bid user-oriented operating systems (like Windows, OSX and Linux) have separate address-spaces and walls between processes.
Upvotes: 3