I am going to go a bit further than David Fang's answer to demonstrate some basic error checking and storage of the players once read.
Note: Starter code lifted from the semi-official answer for this sort of question, Read file line by line.
#include <sstream>
#include <string>
#include <vector>
Need a few includes for this function
std::vector<Player> loadGame()
Define a function that loads all player data from the file into a std::vector
. Why a vector? If the game has multiple players, we've got to put them somewhere, and vector is a damn easy somewhere.
{
std::vector<Player> players;
std::string line;
while (std::getline(infile, line))
Read in a line, exit if no line. getline
documentation.
{
std::string playerName;
int funds, supplies, turn;
std::istringstream iss(line);
Load the line into an easily parsed stream. Use is exactly the same as with cin or infile
if (iss >> playerName >> funds >> supplies >> turn)
Read in all expected input on line. If there are any errors, skip to else case to clean up. Note: Doesn't handle unexpected input on line. We read in all input here rather than later because there is no point building a Player
if the input is bad.
If any of the variables cannot be read and converted to the correct type, the stream will be set into an error state. The if will check this state just as if you'd called good()
. If the input is good, we can set up the Player
all in one call to the constructor rather than having a bunch of calls to the setter. This way anyone using a Player
knows it is all set up and ready to go and merely allocated. With complex objects and multi-threaded systems this is important.
Also the Player
's name is not going to change part-way through the game, so a setter function for name is dodgy.
{
Player player(playerName, funds, supplies, turn);
players.push_back(player);
Make a Player
and put player in vector, or
players.emplace_back(playerName, funds, supplies, turn);
Make a Player
directly in the vector.
}
else
{
One or more errors occurred reading the line. Do whatever you need to do to handle the error
}
}
return players;
}
Return the loaded game to the caller. This may look a little odd. We're passing a list that could be huge to the caller by value. This could mean a very large and expensive copy operation.
Fortunately compilers are not dumb. They know we'll never be using players
in this function again and that it is a local variable and thus will be destroyed as soon as the function goes out of scope. The compiler can do anything it wants to the vector, because this vector is effectively dead. For example, it can rip the vector's guts out and transplant them into another vector in the caller's scope without copying anything and leave the vector for the digital crows to gobble up.
Usage of the function is:
std::vector<Player> players = loadGame();
All together without the running commentary:
#include <sstream>
#include <string>
#include <vector>
std::vector<Player> loadGame()
{
std::vector<Player> players;
std::string line;
while (std::getline(infile, line))
{
string playerName;
int funds, supplies, turn;
std::istringstream iss(line);
if (iss >> playerName >> funds >> supplies >> turn)
{
// Player player(playerName, funds, supplies, turn);
// players.push_back(player);
players.emplace_back(playerName, funds, supplies, turn);
}
else
{
// handle error
}
}
return players;
}