0
votes

I´m trying to create a map of unique_ptr of a base class (entity), where only an unique ID is stored to identify my objects. Now I wanted to create different derived classes (like player, tile,etc. ) which should derive from the base-class to have an unique identification.

How can I pass the memory-location of unique_ptr as an return value without moving it out of my map? My thought is to use the memory-location of the base class, to access the derived functions, when passing derived classes into my map.

P.S. I´m currently working on my own game-engine (still kinda new to cpp)

This is my current EntityManager WIP:

EntityManager.hpp

#pragma once
#include "TSingleton.hpp"
#include "Entity.hpp"
#include <map>
#include <iostream>
#include <memory>

#define g_pEntityManager EntityManager::Get()

class EntityManager : public TSingleton<EntityManager>
{
public:
    EntityManager();
    ~EntityManager();
    // add entity to entity-manager and returns id in entityManager
    int addEntity(std::unique_ptr<Entity> gameObject);

    // get pointer to entityManager
    std::map<int, std::unique_ptr<Entity>> getEntityManager() { return m_EntityManager; };

    // destroy entity
    void killEntity(int entityId);

    // get entity
    std::unique_ptr<Entity> getEntity(int entityId);
private:
    int m_nEntityCounter = 0;

    std::map<int, std::unique_ptr<Entity>> m_EntityManager;
};

EntityManager.cpp

EntityManager::EntityManager()
{
}


EntityManager::~EntityManager()
{
}

int EntityManager::addEntity(std::unique_ptr<Entity> gameObject)
{
    int size = m_EntityManager.size();
    gameObject->setID(size);
    // add entity-object to EntityManager and increment entity_id;
    m_EntityManager.insert(std::make_pair(size, std::move(gameObject)));
    std::cout << "Entity added! " << m_EntityManager.size() << std::endl;
    m_nEntityCounter ++;
    return size;
}

void EntityManager::killEntity(int entityId)
{
    std::map<int, std::unique_ptr<Entity>>::iterator it = m_EntityManager.find(entityId);

    if (it != m_EntityManager.end())
    {
        m_EntityManager.erase(it);
    }
    else
        std::cout << "Couldn`t kill Entity with id: " << entityId << " , because there is no Entity with this id in EntityManager" << std::endl;
}

std::unique_ptr<Entity> EntityManager::getEntity(int entityId)
{
    std::map<int, std::unique_ptr<Entity>>::iterator it = m_EntityManager.find(entityId);
    if (it != m_EntityManager.end())
    {
        if (it->second != nullptr)
        {
            std::unique_ptr<Entity>& found = it->second;
            return std::move(found);
        }
        else
            std::cout << "Pointer to object is NULL!" << std::endl;
    }
    else
        std::cout << "Couldn`t find Entity with id: " << entityId << " in EntityManager" << std::endl;
}
1
You can use std::unique_ptr::get to retrieve the raw encapsulated pointer. Is that what you are asking for?paddy
You should probably create an SSCCE describing what you're trying to do because it's very unclear. Are you trying to pass around the unique_ptr for someone else to populate? Or are you trying to pass around the value it contains without passing around the ownership? If it's the latter, maybe you want shared_ptr instead.kfsone
I´m just trying to get the raw pointer and hoping, that I can access the functions of my derived classes with this raw pointer. @paddy, yeah ... tried to use get() before, but sadly forget about return-type of Entity* instead of std::unique_ptr<Entity> thycFx

1 Answers

1
votes

It's simply not possible to return a unique_ptr by value without moving it.

What you can do however is one of these things:

Return the raw pointer:

Entity* EntityManager::getEntity(int entityId)
{
   return it->second.get();
}

Return a reference to the unique_ptr:

std::unique_ptr<Entity>& EntityManager::getEntity(int entityId)
{
   return it->second;
}

The "problem" with returning by a reference is that you always need to return a valid reference to an object. In the past I've used the strategy of creating for example a static std::unique_ptr<Entity> EmptyEntity object, and getEntity would return it if it can't find one in the map.

For example:

static std::unique_ptr<Entity> EmptyEntity;

std::unique_ptr<Entity>& EntityManager::getEntity(int entityId)
{
    if (it == container.end())
        return EmptyEntity;

    return it->second;
}

The other solution would be returning the unique_ptr by pointer, and return nullptr if it can't find any entity. If you gonna do that it's easier to use Entity* EntityManager::getEntity() instead.