Sign in to follow this  
Shakedown

My post-increment operator isn't working

Recommended Posts

I've used "pp" to represent the plus-plus increment operator since it doesn't appear. So, I have a .txt file with this in it:
First room description.
door
Second room description.
hole
Third room description.
window

The 1,3,5 lines are descriptions of the rooms, and the 2,4,6 lines are the exits available in those rooms. Now I'm trying to read in this information into a vector, and then send this information to a function that creates rooms, like this:
void GenerateRooms(int DIFFICULTY)
{
	vector<string> room_descriptions;

	ifstream descFile ("RoomDescriptions.txt");

	if( descFile.is_open() )
	{
		while( !descFile.eof() )
		{
			string description;
			getline( descFile, description );
			room_descriptions.push_back(description);
		}
		descFile.close();
	}	


	vector<string>::iterator iter = room_descriptions.begin();

	// Initialize the various Rooms.  
	// The first parameter is the description, 
	// the second parameter is the exits, and 
	// the third parameter is the hint.
	// the fourth parameter is the chance that a monster will spawn in the room
	AddRoom(*(iter)pp, *(iter)pp, "Try the door.", DIFFICULTY);
	AddRoom(*(iter)pp, *(iter)pp, "Try the hole.", DIFFICULTY);
	AddRoom(*(iter)pp, *(iter)pp, "Try the trapdoor.", DIFFICULTY);
	AddRoom(*(iter)pp, *(iter)pp, "none.", DIFFICULTY);

So in my vector I want the 0th element to be the room description, the 1st element to be the exits, the 2nd element the second room description, the 3rd element the second room's exit, ... But I can't get the pp operator to work correctly. When I run this I get this output:
door
Exits: First room description.

Where those lines should be switched. What is the correct placement of the pp operator? I've tried every possibility I could find, although perhaps some funky parentheses placement is needed.

Share this post


Link to post
Share on other sites
Hmmm..., I don't understand what all the trouble is. You are making things more complex then they need to be.

Here is what I would do:

void GenerateRooms(int DIFFICULTY)
{
vector<string> room_descriptions;

ifstream descFile ("RoomDescriptions.txt");

if( descFile.is_open() )
{
while( !descFile.eof() )
{
string description;
getline( descFile, description );
room_descriptions.push_back(description);
}
descFile.close();
}

for( int i = 0; i < room_descriptions.size(); i += 2 )
AddRoom( room_descriptions.at( i ), room_descriptions.at( i + 1 ), DIFFICULTY );
}



As you can see I have removed the hint because it did not work with the loop, but you should probably be loading that from a file anyways.

Share this post


Link to post
Share on other sites
Yeah I was going to put all the info in the .txt file and run it through a for loop just as you did, but I couldn't get the pp operator to work. I'll just go straight to the for loop I guess, I'll go see if it works.

Good lord, this error was printed straight to the console:
This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information."

Uhh...

EDIT: Ah found the problem. I added the hint into the for loop, but I didn't change the increment in the for loop to add 3 instead of 2. So I changed it to 3 and it works fine now.

Share this post


Link to post
Share on other sites
Don't test for end-of-file. The end of file flag is only set *after* you make an unsuccessful read.

Instead, test the stream itself. A stream has an implicit convertion to a pointer, which if NULL indicates that the stream is in an error state (for whatever reason, including EOF). All stream operations (such as << or >>, and std::getline) return the stream itself. We can simply test the return value of std::getline to see if it succeeded.

So:

if( descFile.is_open() )
{
std::string description;
while( std::getline( descFile, description ) )
{
room_descriptions.push_back(description);
}
// dont need this, std::fstream objects close themselves
// descFile.close();
}




With this, if the stream isnt open std::getline will fail on the first read so we dont even need to test if it opened correctly (unless you wish to alert the user that the file didn't open...).

Like so:

std::string description;
while( std::getline( descFile, description ) )
{
room_descriptions.push_back(description);
}




You need to be very careful with you other loop, for example test if there are an even number of entries to ensure you don't access invalid memory.

Share this post


Link to post
Share on other sites
I'm assuming you're warning me to make sure I have an even number of entries because of the i += 2 increment in the for loop? I changed that to increment by 3 so I can have more in the .txt file, but, why would it matter if I have an even or odd number of entries? I don't see how I can access invalid memory. For every room there is a description, an exit, and a hint that is read from the .txt file. I can't think of how I would run into invalid memory.

If there were 100 rooms, that would be a vector size of 300, so the for loop would run 100 times. If there were 99 rooms, that would be a vector size of 297, and the for loop would run 297/3 = 99 times.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shakedown
I'm assuming you're warning me to make sure I have an even number of entries because of the i += 2 increment in the for loop? I changed that to increment by 3 so I can have more in the .txt file, but, why would it matter if I have an even or odd number of entries? I don't see how I can access invalid memory. For every room there is a description, an exit, and a hint that is read from the .txt file. I can't think of how I would run into invalid memory.

If there were 100 rooms, that would be a vector size of 300, so the for loop would run 100 times. If there were 99 rooms, that would be a vector size of 297, and the for loop would run 297/3 = 99 times.


You are reading in data from an external source. All external data should be validated. If you don't do this, your program will crash sometime. You might accidentally forget to add a description to some room, for example. Your program may crash immediately, or you could end up having some form of subtle memory corruption that will leave you scratching your head.

If you intend on releasing your game, this is even more important. You know that your program will crash if you corrupt your file, users may not.

Seeing as you know this possibility exists, its almost irresponsible not to fix it.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Quote:
Original post by Shakedown
I'm assuming you're warning me to make sure I have an even number of entries because of the i += 2 increment in the for loop? I changed that to increment by 3 so I can have more in the .txt file, but, why would it matter if I have an even or odd number of entries? I don't see how I can access invalid memory. For every room there is a description, an exit, and a hint that is read from the .txt file. I can't think of how I would run into invalid memory.

If there were 100 rooms, that would be a vector size of 300, so the for loop would run 100 times. If there were 99 rooms, that would be a vector size of 297, and the for loop would run 297/3 = 99 times.


You are reading in data from an external source. All external data should be validated. If you don't do this, your program will crash sometime. You might accidentally forget to add a description to some room, for example. Your program may crash immediately, or you could end up having some form of subtle memory corruption that will leave you scratching your head.

If you intend on releasing your game, this is even more important. You know that your program will crash if you corrupt your file, users may not.

Seeing as you know this possibility exists, its almost irresponsible not to fix it.


How do I validate it? Divide the vector size by 3 and if its not divisible then there's a missing line?

Share this post


Link to post
Share on other sites
Quote:
Original post by Shakedown
How do I validate it? Divide the vector size by 3 and if its not divisible then there's a missing line?


Almost, you cannot use division directly due to integer division. You could just drop the last entries until the vector is of correct size:

int numToDrop = vec.size() % 3;

if( numToDrop ) {
std::cerr << "warning, " << numToDrop << " excess room description lines dropped\n";
vec.erase( vec.end() - numToDrop, vec.end() );
}


Share this post


Link to post
Share on other sites
I just did

if(room_descriptions.size() % 3 != 0)
{
cerr << "Error. Missing line in .txt file.";
done = true;
}


done is a bool that I check at the beginning of my game loop, so it'll just display the error and then skip over the game loop and exit the game. Why do you say this doesn't work with integers?

Share this post


Link to post
Share on other sites
Quote:
Original post by Shakedown
I just did

if(room_descriptions.size() % 3 != 0)
{
cerr << "Error. Missing line in .txt file.";
done = true;
}


done is a bool that I check at the beginning of my game loop, so it'll just display the error and then skip over the game loop and exit the game. Why do you say this doesn't work with integers?


Test out integer division:

for( int i = 1 ; i < 4 ; ++i )
std::cout << i << " / 3 is " << ( i / 3 ) << '\n';


Integer division truncates the answer, drops anything that would appear after the decimal place.

Share this post


Link to post
Share on other sites
You're right, but that doesn't matter in my case does it? If there is a line missing, then % 3 != 0, and then it'll tell me there's a line missing. That's all I care about, right? That it tells me there's a line missing and exits.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shakedown
You're right, but that doesn't matter in my case does it? If there is a line missing, then % 3 != 0, and then it'll tell me there's a line missing. That's all I care about, right? That it tells me there's a line missing and exits.


Yes. Its just when you said "Divide the vector size by 3" I just mentioned that division wouldn't work. Then you asked why, or so I thought.

Share this post


Link to post
Share on other sites
    AddRoom(*(iter)++, *(iter)++, "Try the door.", DIFFICULTY); 
There are two major problems with that line:
  1. The order of evaluation of function parameters is unspecified. You don't know which parameter is evaluated first.
  2. The post-increments will be done sometime before the function is called, but you don't know when. They are not necessarily done right after each parameter is evaluated.
Here is a similar situation:
        int i = 1;
foo( i++, i++ );
...
void foo( int a, int b )
{
cout << a << ", " << b;
}
Any of the following results are possible:
    1, 1
1, 2
2, 1

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