Sign in to follow this  
gah_ribaldi

populating a class' variables form a text file - c++

Recommended Posts

Hi, I am trying to load data from a text file to populate an instance of a class "player" with the following data types: std::string name int age float chanceToHit all three have setters, and I've gotten as far as player.setName( then my thinking process grinds to a halt. Could someone kick-start me? Also, will ints and floats populate ok? My text file is newline delimited, so looks like this in notepad: Fred 16 55.28 Mark 17 32.9 Jim 20 99

Share this post


Link to post
Share on other sites
WEll, I've been having a bash at a version of this and have come up with:


void loadItems(ListOfItems &itemList)
{
// open file
std::ifstream itemFile;
itemFile.open("items.txt");
// prepare variables to hold data from file
std::string line1;
int line2;
float line3;
float line4;
Item loaderItem;

// run through file grabbing these four lines
// then using them to populate loaderItem
// which is then pushed onto the List
while (! itemFile.eof())
{
std::getline(itemFile, line1);
loaderItem.setDescription(line1);

itemFile >> line2;
loaderItem.setRef(line2);

itemFile >> line3;
loaderItem.setWeight(line3);

itemFile >> line4;
loaderItem.setPrice(line4);

itemList.push_back(loaderItem);
}
itemFile.close();
}




This compiles and runs, but the function never passes comtrol back to the main application. I'm only using three items worth of data in the text file.

ListOfItems has been typedeffed as a vector of items.

Share this post


Link to post
Share on other sites
Here is how I might write that:

istream &operator>>( istream &in, Item &item )
{
std::string name;
int ref;
float weight, price;
std::getline(in,name);
in >> ref;
in >> weight;
in >> price;
item.setName(name);
item.setRef(ref);
item.setWeight(weight);
item.setPrice(price);
return in;
}

void loadItems(ListOfItems &itemList)
{
std::ifstream file("fileitems.txt");

Item item;

while (file >> item)
{
itemList.push_back(item);
}
}



What is probably happening is that one of the reads is failing. When a std::fstream tries a read and fails, it sets an internal flag that tells it not to perform any more reads. As such, it loops continuously, because the end of the file is not reached. Your vector is probably growing very fast.

Note how I check if the read succeeds, the read itself is the loop control condition. Note that this only does the roughest of sanity checks, it will stop processing the file half way if the file is malformed there.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Here is how I might write that:
*** Source Snippet Removed ***

What is probably happening is that one of the reads is failing. When a std::fstream tries a read and fails, it sets an internal flag that tells it not to perform any more reads. As such, it loops continuously, because the end of the file is not reached. Your vector is probably growing very fast.

Note how I check if the read succeeds, the read itself is the loop control condition. Note that this only does the roughest of sanity checks, it will stop processing the file half way if the file is malformed there.


Thanks. I'm not really sure what's going on in what you've put there or how I would implement it though.

Could you talk me throuh what this does? Copying and pasting gets me there faster... right until I hit the same problem some other time.

Share this post


Link to post
Share on other sites
I actually solved this just now (yes, I keep trying to solve the problem while waiting for forum answers, aren't I a good chap?) by changing the getline line to

itemFile >> line1;

but I'd still like to know how your code works.

Cheers

Share this post


Link to post
Share on other sites
Quote:
Original post by gah_ribaldi
Quote:
Original post by rip-off
Here is how I might write that:
*** Source Snippet Removed ***

What is probably happening is that one of the reads is failing. When a std::fstream tries a read and fails, it sets an internal flag that tells it not to perform any more reads. As such, it loops continuously, because the end of the file is not reached. Your vector is probably growing very fast.

Note how I check if the read succeeds, the read itself is the loop control condition. Note that this only does the roughest of sanity checks, it will stop processing the file half way if the file is malformed there.


Thanks. I'm not really sure what's going on in what you've put there or how I would implement it though.

Could you talk me throuh what this does? Copying and pasting gets me there faster... right until I hit the same problem some other time.


C++ is designed so that you can use your own types in the same way as basic types. This is why it allows operator overloading.

The first thing I did was to define a function telling an istream how to read an item. The function prototype takes a reference to an istream and an item, to mimic the way the function is "called" stream >> item. This becomes operator>>(stream,item). The function should return the stream it is passed, this is why its return value is an istream reference.

The read itself is similar to your own.

LoadItems is a lot shorter. You may have noticed that I dropped a lot of superfluous actions on the filestream object. For example, instead of manually calling open() I passed the file name to the constructor. Similarly, std::fstream is an RAII object, so it cleans up after itself, so the call to close() is unnecessary.

Like I said, when a read operation fails the stream sets a 'fail' flag. If the end of the stream is encountered the stream sets an 'eof' flag. When evaluated in a conditional context, the stream returns a true value if the flags are clear. Otherwise it returns a value that is false*. This means that if we write:

if( stream )
{
// code
}



Then the "code" will only run if the stream hasn't failed or hasn't reached the end of file. This links us back to my little function I wrote for operator>>(). Remember it returns the istream reference?

So, effectively we have:

while( operator>>(file,item) )
{
}



The operator>> will return the reference to the variable 'file', evaluate it in a conditional context and continue the loop as long as the end of file or a failure has not occurred. It is pretty much the same (but shorter) than this:

while (file)
{
Item item;
std::string name;
int ref;
float weight, price;

std::getline(file,name);
file >> ref;
file >> weight;
file >> price;

item.setName(name);
item.setRef(ref);
item.setWeight(weight);
item.setPrice(price);

if( file )
{
itemList.push_back(item);
}
}




* technically, I believe it returns a null/not null pointer, but the effect is the same.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this