Reputation: 446
I am creating a simple demo project but I am getting stuck at adding a unique_ptr
to an unordered list, somehow it adds the key but not the pointer and later on when I try to call a method on the pointer I get the 'this was nullptr error'.
I have a base class Scene
that is responsible for storing the pointers and adding them to the map like this:
void Scene::addGameObject(const std::string& name, const GameObjectParams& params)
{
m_objects.try_emplace(name, std::make_unique<GameObject>(params));
}
bool Scene::containsGameObject(const std::string& name)
{
if (m_objects[name] != NULL)
return true;
return false;
}
GameObject& Scene::getGameObject(const std::string& name)
{
auto it = m_objects.find(name);
if (it != m_objects.end())
return *it->second;
}
void Scene::drawScene()
{
for (const auto& object : m_objects)
object.second->draw(); // <--------here the error gets thrown
}
If I call this method from a class that has a scene
as member it works fine, per example:
//GameLayer.h
class GameLayer
{
private:
// GameScene is derived class from Scene
GameScene m_gameScene;
};
//GameLayer.cpp
m_gameScene.addGameObject(
"player",
{
Vector3f(0.0f, 0.0f, 1.0f),
Vector3f(100.0f, 70.0f, 1.0f),
Quaternion(),
Vector4f(1.0f),
fighter
}
);
But now when I try to add a new object from the derived class itself it adds the key but no pointer
void GameScene::spawnLaser(Vector3f pos)
{
for (int i = 0; i < 100; i++)
{
std::string name = std::to_string(i);
if (!this->containsGameObject(name))
{
m_lasers.emplace_back(name);
this->addGameObject(
"laser",
GameObjectParams {
Vector3f(0.0f, 0.0f, 1.0f),
Vector3f(100.0f, 70.0f, 1.0f),
Quaternion(),
Vector4f(1.0f),
nullptr
}
);
return;
}
}
}
The GameObject
is the object that should be created with std::make_unique
GameObject::GameObject(const GameObjectParams& params)
: m_position(params.position.x, params.position.y, params.position.z),
m_scale(params.scale.x, params.scale.y, params.scale.z),
m_rotation(),
m_texture(params.texture),
m_color(params.color)
{
}
void GameObject::setTexture(cheetah::Texture* texture)
{
m_texture = texture;
}
void GameObject::setPosition(const cheetah::Vector3f& position)
{
m_position.x = position.x;
m_position.y = position.y;
m_position.z = position.z;
}
void GameObject::translate(const cheetah::Vector3f& position)
{
m_position.x += position.x;
m_position.y += position.y;
m_position.z += position.z;
}
void GameObject::draw()
{
// 'this was nullptr' gets thrown here
if (m_texture != nullptr)
{
Renderer2D::drawQuad(DrawTexturedQuadParams{ m_position, m_scale, m_rotation, Vector4f(1.0f), m_texture });
}
else
{
Renderer2D::drawQuad(DrawQuadParams{ m_position, m_scale, m_rotation, m_color });
}
}
It seems as if make_unique
doesn't create a new object but I have no idea why.
Upvotes: 0
Views: 312
Reputation: 595827
In this code:
bool Scene::containsGameObject(const std::string& name)
{
if (m_objects[name] != NULL)
return true;
return false;
}
If name
does not exist in the map, the map's operator[]
will add name
with a default-constructed std::unique_ptr
that holds a nullptr
. You need to use m_objects.find(name)
instead of m_objects[name]
:
bool Scene::containsGameObject(const std::string& name) const
{
return (m_objects.find(name) != m_objects.end());
}
In this code:
GameObject& Scene::getGameObject(const std::string& name)
{
auto it = m_objects.find(name);
if (it != m_objects.end())
return *it->second;
}
If name
is not found in the map, the return value is indeterminate. You need to either:
nullptr
if name
is not found (and then update the caller to check for nullptr
):GameObject* Scene::getGameObject(const std::string& name)
{
auto it = m_objects.find(name);
if (it != m_objects.end())
return it->second.get();
return nullptr;
}
name
is not found:GameObject& Scene::getGameObject(const std::string& name)
{
// std::unordered_map::at() throws std::out_of_range if the key is not found...
return *(m_objects.at(name)->second);
}
Upvotes: 4