Manspider
Manspider

Reputation: 353

Emplacing and modifying object in vector trough reference

I got this simple creature and AI classes. The Goal is to plug an AI to a creature and give to said AI the creature's reference.

Creature

class Creature
{
public:
    explicit Creature(std::string&& name) : m_name(name) {}

    void setAI(std::shared_ptr<AI>&& behavior)
    { m_behavior = std::move(behavior); }

    void greet() { m_behavior->action(); }

    const std::string& getName() const { return m_name; }

private:
    std::shared_ptr<AI> m_behavior;
    std::string m_name;
};

AI

class AI
{
public:
    explicit AI(Creature& creature) : m_creature(creature) {}

    void action() { std::cout << m_creature.getName() << std::endl; }

private:
    Creature& m_creature;
};

Now depending in the order of action when I create the creature and set the AIs I get different result and fail to understand why.

Example 1: Not working. Only the last creature has a valid AI.

std::vector<Creature> atlas;

Creature& quokka = atlas.emplace_back(Creature("Quokka"));
quokka.setAI(std::make_shared<AI>(quokka));

Creature& wombat = atlas.emplace_back(Creature("Wombat"));
wombat.setAI(std::make_shared<AI>(wombat));

Creature& bilby = atlas.emplace_back(Creature("Bilby"));
bilby.setAI(std::make_shared<AI>(bilby));

for (Creature& creature : atlas) { creature.greet(); }

Example 2: This is working perfectly

atlas.emplace_back(Creature("Quokka"));
atlas.emplace_back(Creature("Wombat"));
atlas.emplace_back(Creature("Bilby"));

for (Creature& creature : atlas)
{
    creature.setAI(std::make_shared<AI>(creature));
}

Where is the difference and why does example 1 fails to work ?

Upvotes: 0

Views: 27

Answers (1)

super
super

Reputation: 12928

This is caused by the fact that when a std::vector grows it will reallocate it's content. That means that all pointers and references to that vector will be invalidated.

You are storing a reference to a Creature in you AI class, and it get invalidated in you first example, since you add object to the vector after you have obtained the references.

In your second example, all the object are added first, then you take the references to them. Hence all the references are still valid.

Upvotes: 2

Related Questions