GIDForums  

Go Back   GIDForums > Computer Programming Forums > C++ Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 17-May-2005, 04:29
Clive73 Clive73 is offline
New Member
 
Join Date: May 2005
Location: Bristol
Posts: 9
Clive73 is on a distinguished road

STL troubles saving and finding


Hello all,

I'm experiencing a few problems saving some STL data for a code my boss wanted written. The data is saved (I think) but when read back in it's all blank - though the correct number of objects are loaded. The initial employees are added and displayed fine, it's just the saving that's the problem.

CPP / C++ / C Code:
#include <fstream>
#include <iostream>
#include <list>
using std::cin;
using std::list;
using std::iterator;
using std::ios;
using std::ofstream;
using std::ifstream;

class employee
{
 ... info here ...
};

int main()
{
     std::list<employee> outStaff;
     std::list<employee>::iterator p;
     std::list<employee>::iterator r;

  ... employee data taken ...

     std::ofstream output("staffdata",ios::binary);
     if (!output)
     {
	std::cout << "\nCould not open the file!!\n\n";
     }
     else
     {
          for (p=ourStaff.begin();p!=ourStaff.end();p++)
          {
               output.write((char*)&p,sizeof(p));
          }
          output.close();
     }

   ...  clear the list then, to read it back in ...

     std::ifstream fin("staffdata",ios::binary);
     if (!fin)
     {
          std::cout << "\nCouldn't open file\n";
     }
     else
     {
          while (!fin.eof())
          {
               fin.read((char*)&r, sizeof(r));
	  ourStaff.push_back(*r);
          }
      }

  ...  display data here ...


No errors are appearing and as far as I can tell the data is being saved.

I'm also troubled with the find and sort commands. All the examples I've seen create a simple list such as list<int> theList, and that's easy to sort. But how can I search on a specific class variable (such as employee number)?

Many thanks,

Clive.
  #2  
Old 19-May-2005, 09:03
QED's Avatar
QED QED is offline
Member
 
Join Date: Feb 2005
Location: Hudson Valley, NY
Posts: 231
QED is a jewel in the roughQED is a jewel in the roughQED is a jewel in the rough
Quote:
Originally Posted by Clive73
No errors are appearing and as far as I can tell the data is being saved.
First, let me comment that I actually encountered a segmentation fault during runtime with a small program designed to approximate your example. If you did not observe a runtime error, it is likely a result of different object code generated by your compiler. However, it is easy to write a progam that doesn't crash, but that has errors in it.

In attempting to read back in your employee data, you seem to be trying to create a new employee object without calling a constructor! While this may in fact be possible (though I can't think of a good reason to do so, and for complicated objects it could be prohibitive), your code does something very different.
When saving, you are actually writing to file the bytes that describe the iterator p, not the bytes that describe the employee object pointed to by p. Now, when reading back in to the iterator r, you are retrieving the iterator information; that is, primarily, the addresses of the employee objects that used to reside in the list outStaff. However, when clearing the list, you have destroyed those employees, and the addresses you just read back in don't point to valid employee objects any more. See the code example at the end of this post, which uses two lists and does not clear the first, to demonstrate what I'm talking about. Then uncomment the code where we clear the first list, and let the fun ensue!

Rather than try to desribe how to go about doing what you want with this technique, I recommend that you design your employee class so as to let the object itself manage the save and load. Perhaps, add to the employee class the following:
1. constructor that takes an array of bytes (char[]) and a size (# bytes) as arguments
2. serialize() or toBytes() or some such method that returns a char[].
Let the employee object decide what data needs to be saved, and then load it in the constructor itself.

Quote:
Originally Posted by Clive73
But how can I search on a specific class variable (such as employee number)?
In order to do this, you need to define a comparator for employee objects that the STL algorithms can use to decide precedence. The algorithms allow you to pass in your own custom functor (function object) to use for comparisons, but by default they use the less than operator.

So, the quickest way is to simply overload operator< for employee objects.
CPP / C++ / C Code:
bool operator < (employee const& emp1, employee const& emp2);
I'll leave it to you to define the function since I don't know what your employees really are. Keep in mind that if you need to compare any private members, you probably have to make this operator a friend function.

Ask any further questions, and maybe give this another try. I'll be happy to help out again (assuming I have even helped at all now) if I can.

Matthew


Here's the example code I mentioned:
CPP / C++ / C Code:
#include <fstream>
#include <iostream>
#include <list>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::iterator;
using std::ios;
using std::ofstream;
using std::ifstream;

class employee
{
public:
  employee(int id, std::string const& name) : _id(id), _name(name) {}
  int _id;
  std::string _name;
};

int main ()
{
  std::list<employee> outStaff, outStaff2;
  std::list<employee>::iterator p;
  std::list<employee>::iterator r;

  cout << "Initializing employee list" << endl;
  outStaff.push_back(employee(1, "robert robertson"));
  outStaff.push_back(employee(2, "peter p petersen"));
  outStaff.push_back(employee(3, "georgina george"));

  cout << "Writing employee data to file" << endl;
  std::ofstream output ("staffdata", ios::binary);
  if (!output)
  {
    std::cout << "\nCould not open the file!!\n\n";
  }
  else
  {
    for (p = outStaff.begin(); p != outStaff.end(); p++)
    {
      output.write((char*)&p, sizeof(p));
    }
    output.close();
  }

  // leave out the following so that the objects are not destroyed
  //cout << "Clearing employee list" << endl;
  //outStaff.clear();

  cout << "Reading employee data from file" << endl;
  std::ifstream fin("staffdata", ios::binary);
  if (!fin)
  {
    std::cout << "\nCouldn't open file\n";
  }
  else
  {
    while (!fin.eof())
    {
      fin.read ((char*)&r, sizeof(r));
      outStaff2.push_back(*r);
    }
  }

  cout << "Employees in list are: " << endl;
  for (p = outStaff2.begin(); p != outStaff2.end(); ++p)
  {
    cout << "ID: " << p->_id << " NAME: " << p->_name << endl;
  }

  cout << "Done." << endl;
  return 0;
}
  #3  
Old 19-May-2005, 09:50
Clive73 Clive73 is offline
New Member
 
Join Date: May 2005
Location: Bristol
Posts: 9
Clive73 is on a distinguished road
Thanks for this. Very much a newbie to all this and so confusion levels are still high but gives me a starting point.

Clive.
 
 

Recent GIDBlogUS Elections and the ?Voter?s Responsibility? by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 06:32.


vBulletin, Copyright © 2000 - 2008, Jelsoft Enterprises Ltd.