Search code examples
c++vectorpolymorphismreference-wrapper

Polymorphism in C++ with a vector with base classes and reference_wrapper


I need to use polymorphism in C++ for objects which are stored in a vector.

Understand from other questions that the objects in the vector need to be stored by reference since otherwise object slicing occurs.

My understanding is that std::reference_wrapper would be a good fit, but I'm having some issues implementing it.

ActorRecordingItem is the base class and ActorVehicleEnterRecordingItem is an example of a class which needs polymorphism (inherts from ActorRecordingItem via ActorVehicleRecordingItem)

    class ActorRecordingItem {
protected:
    DWORD m_ticksAfterRecordStart;
    Ped m_actorPed;
    Vector3 m_location;
    DWORD m_ticksDeltaCheckCompletion;
public:
    ActorRecordingItem(DWORD ticksStart, Ped actorPed, Vector3 location);
    virtual void executeNativesForRecording(Actor actor);
    virtual bool isRecordingItemCompleted(Actor actor, Vector3 location);
    virtual std::string toString();
};

class ActorVehicleEnterRecordingItem : public ActorVehicleRecordingItem {
protected:
    int m_vehicleSeat;
    float m_enterVehicleSpeed;
public:
    ActorVehicleEnterRecordingItem(DWORD ticksStart, Ped actor, Vector3 location, Vehicle veh, int vehicleSeat,float enterVehicleSpeed);
    std::string toString() override;
    void executeNativesForRecording(Actor actor) override;
    bool isRecordingItemCompleted(Actor actor, Vector3 location) override;
};

The vector with the objects which needs polymorphism is stored in another class Actor. It's currently defined as

class Actor
{
private:
    std::vector<std::reference_wrapper<ActorRecordingItem>> m_actorRecordingItems;
public:
    Actor();
    Actor(Ped ped);
    void setRecording(std::vector<std::reference_wrapper<ActorRecordingItem>> actorRecordingItems);
    std::vector<std::reference_wrapper<ActorRecordingItem>> getRecording();
    std::reference_wrapper<ActorRecordingItem> getRecordingAt(int index);
};

With implementation of the key methods as

void Actor::setRecording(std::vector<std::reference_wrapper<ActorRecordingItem>> actorRecordingItems)
{
    m_actorRecordingItems = actorRecordingItems;
}

std::vector<std::reference_wrapper<ActorRecordingItem>> Actor::getRecording()
{
    return m_actorRecordingItems;
}

std::reference_wrapper<ActorRecordingItem> Actor::getRecordingAt(int index)
{
    return m_actorRecordingItems[index];
}

The actorRecordingItems are created in a separate method and assigned to the actor. This is done through

std::vector<std::reference_wrapper<ActorRecordingItem>> actorRecording;
actorRecording.reserve(1000);

ActorVehicleEnterRecordingItem recordingItem(ticksSinceStart, actorPed, actorLocation, actorVeh, seat, enterSpeed );
actorRecording.push_back(recordingItem);

actor.setRecording(actorRecording);

Lastly is the location where I want to use them and require the polymorphism.

std::reference_wrapper<ActorRecordingItem> recordingItem = actor.getRecordingAt(recordingPlayback.getRecordedItemIndex());

recordingItem.get().executeNativesForRecording(actor);

The last line appears to cause the program to crash. I'm really a bit lost on where to start looking into this problem, so any assistance would be much appreciated

PS sorry for the very long question :)


Solution

  • The problem is in these lines:

    ActorVehicleEnterRecordingItem recordingItem(ticksSinceStart, actorPed, actorLocation, actorVeh, seat, enterSpeed );
    actorRecording.push_back(recordingItem);
    

    What is happening here is that you create a local variable and push a reference to the local variable to the vector. The reference becomes invalid as soon as the variable recordingItem goes out of scope. std::reference_wrapper is exactly what the name states - it is a wrapper for a reference and it doesn't do any kind of management of resources. You can circumvent this problem by having a vector of std::unique_ptr, std::shared_ptr or if you want to avoid dynamic allocation for each element - boost::variant<> (in this case you will need to specify all the potential types that could be in the vector).