(Dangling?) Reference returned from function does not "work"

128 views Asked by At

I followed V. Romeo's Tutorial on entity management (on GitHub & Youtube).

I then tried to rewrite the classes CEntity, CComponent and for testing CPosition(mostly from memory from Romeo's video/code). The problem i encounter is that, in my main i create a CEntity on the stack & add a component. When i add the component via addComponent() i grab the reference to the newly created component, returned by addComponent().

When i now want to modify the component through the reference returned, the changes i make are not reflected back to the entity('s component). Looks like a dangling reference to me, but i am unable to find the errors i made.

Can anyone please point out what i am doing wrong here?

Follwing my CEntity class:

#include <array>
#include <bitset>
#include <memory>
#include <cassert>
#include <stdexcept>

namespace inc
{

using ComponentID = unsigned int;

ComponentID getNewID()
{
    static ComponentID id = 0;
    return id++;
}

template <typename T>
ComponentID getComponentID()
{
    static ComponentID component_id = getNewID();
    return component_id;
}

// Forward declarations used by CEntity:
struct CComponent;

class CEntity
{
public:
    static const ComponentID MAX_COMPONENTS = 30;
    using ComponentArray                    = std::array<std::unique_ptr<CComponent>, CEntity::MAX_COMPONENTS>;
    using ComponentBitset                   = std::bitset<MAX_COMPONENTS>;

public:
    CEntity()
    {
    }

    ~CEntity()
    {
    }

    template <typename T, typename... TArgs>
    T& addComponent(TArgs&&... Args)
    {
        // Ensure that CComponent is base of T:
        static_assert(std::is_base_of<CComponent, T>::value, "CEntity::addComponent(): Component has to be derived from CComponent.");

        // Get id for component type
        auto component_id = getComponentID<T>();
        assert(component_id <= MAX_COMPONENTS);

        // Create component
        auto component     = std::make_unique<T>(std::forward<TArgs>(Args)...);
        auto component_ptr = component.get();

        // Initialize the component
        component->entity = this;
        component->init();

        // Store component
        components_[component_id] = std::move(component);

        // Set component flag
        component_bitset_[component_id] = true;

        return *component_ptr;
    }

private:
    ComponentArray components_;
    ComponentBitset component_bitset_;
};

Here my CComponent & CPosition classes:

// Forward required by CComponent
class CEntity;

// Abstract base class for components
struct CComponent
{
    using TimeSlice = float;

    // Pointer to parent entity
    CEntity* entity;

    virtual ~CComponent() {}

    virtual void init() {}
    virtual void update(const TimeSlice DT) {}
    virtual void draw() const {}
};

struct CPosition : public CComponent
{
    sf::Vector2f position{0,0};
};

And my main function:

#include "Entity.h"
#include "ComponentCollection.h"
int main()
{
    inc::CEntity entity;

    auto pos = entity.addComponent<inc::CPosition>();
    pos.position.x = 1;
    return 0;
}
1

There are 1 answers

0
Barry On BEST ANSWER

The issue is here:

auto pos = entity.addComponent<inc::CPosition>();
^^^^^

addComponent() returns a reference, and everything in that function is fine (no dangling reference issue as far as I can tell). But auto does not deduce a reference type unless you tell it to - so you're simply making a copy right there. The solution is just to tell it to deduce a reference:

auto& pos = entity.addComponent<inc::CPosition>();