tothemax
tothemax

Reputation: 115

Correct Syntax for Updating a Classes Vector Elements

I have a question regarding classes and how their members can be updated.

So basically, I have a simple class

class Player
{
public:
    Player();
    std::vector <std::string> hand = {"r4", "r1", "g5"};
};

Player::Player()
{

}

and I added instances of these classes to another vector

std::vector <Player> players;

            Player p1;
            Player p2;

            players.push_back(p1);
            players.push_back(p2);

But then I try to update the vectors of the initialized classes inside the vector storing the classes

            //doesn't work
            //p1.hand.push_back("test1");
            //p2.hand.push_back("test2");

            //works
            players[0].hand.push_back("test1");
            players[1].hand.push_back("test2");

       for (int i = 0; i < 2; i++) 
            std::cout << players[i].hand[(players[i].hand.size() - 1)] << std::endl;

I am confused why it is not adding the test strings to the vectors of the classes in the players array with the first method. Is it because it's not the same instance of the class as when I first initialized it? If someone could clarify this for me that would much appreciated. Thanks!

Upvotes: 0

Views: 270

Answers (1)

user4442671
user4442671

Reputation:

In C++, there is (mostly) no value types vs reference types duality. Everything is a value unless specified otherwise.

std::vector<Player> is a vector of Player instances, not a list of references to instances of Player. So when you do players.push_back(p1);, this has to make a copy of p1 so that the instance of Player in the vector belong to it.

There are ways to have vectors of references, but it's rarely the way to go. The problem with containers of non-owning references is that you must somehow be absolutely certain that every single instance referred to by the container outlives the container itself, and that can get really tricky.

In a case like yours, a more typical approach would be to have the vector be the owner of the instances. And if you absolutely must have p1 and p2, they can be variable references pointing back into it:

// Initialize the vector with 2 default-constructed players
std::vector <Player> players(2);

// ...

{
  Player& p1 = players[0];

  p1.hand.push_back("test1");
  p1.hand.push_back("test2");
  p1.hand.push_back("test3");
}

However, you need to be careful, as p1 and p2 will become invalid if you resize the vector.

Upvotes: 3

Related Questions