C++映射是否可以包含指向我的任意类的指针

Can a C++ map contain a pointer to my arbitrary class?

本文关键字:我的 任意类 指针 包含指 映射 是否 C++      更新时间:2023-10-16

我正在编写一个小型游戏引擎作为夏季项目,并且在STL映射方面有点困难。

我已经声明了一个类RenderList来保存对象。RenderList将被传递给Renderer类来完成这项工作。

RenderList具有map<std::string,Entity*> objects;

这一切都有效,直到我试图从地图上获得Entity*,我得到了:

断言失败,在vc/include/xtree中表达式:映射/设置迭代器不可取消引用。

这是用于检索指针的代码。

Entity* RenderList::getByName(std::string str){
    return objects.find(str)->second;
}

我需要它来容纳指针,而不是实际的对象,因为我需要Entity的不同子类。

我是STL的新手,我应该不在映射中存储指针吗?

当然应该允许我这样做,还是存储对象更好?

最后,我只是做错了吗!?

希望这个问题不是重复的,我事先做了快速搜索。此外,如果这在GameDev堆栈中会更好,我会把它发布在那里。

如果找不到键,则map::find(key)返回一个"结束后"迭代器,即map::end()返回的值,并且该迭代器不指向任何元素,因此无法取消引用。在取消引用find之前,您不会检查它返回的内容。

你确定他们的钥匙在地图上吗?

如果找不到密钥,您可能想做一些类似于返回NULL的事情,可以通过将返回的迭代器与end进行比较来检查,例如

Entity* RenderList::getByName(std::string str){
  map_type::iterator it = objects.find(str);
  if (it == objects.end())
    return NULL;
  return it->second;
}

其中RenderList定义typedef:

typedef map<std::string,Entity*> map_type;

(注意:我总是让我的类为我用作实现细节的容器定义typedef,因为写map_type::iterator比写map<std::string,Entity*>::iterator容易得多,而且如果我把容器改成其他东西,我不必把所有使用它的代码都改成map<std::string,shared_ptr<Entity>>::iterator,我可以把它保留为map_type::iterator,它仍然可以完美地工作。)

关于一般设计,您可以存储boost::shared_ptr<Entity>std::tr1::shared_ptr<Entity>而不是原始指针吗?管理对象的生存期会更安全、更简单。

这可能意味着您要查找的名称在映射中不存在。如果键不存在,find方法将返回映射的结束迭代器,该迭代器实际上是不可解引用的。

如果"未找到"的情况是自然发生的,那么你可以做这个

Entity* RenderList::getByName(std::string str){
    map<std::string,Entity*>::iterator it = objects.find(str);
    return it != objects.end() ? it->second : NULL;
}

从而将处理这种情况的责任传递给呼叫者。

如果"未找到"的情况不应该发生,要么抛出异常,要么至少执行

assert(it != objects.end());

其中一个错误是,您需要处理没有与str匹配的条目的情况。然而,我不确定具体的错误是什么,因为我(遗憾地)在地图上做了同样的搜索来检索指针。。

如果映射不包含传递给find方法的键,那么它将返回objects.end()。取消引用这是一个运行时错误,很可能会导致您看到的错误。尝试:

map<std::string,Entity*>::iterator findIt;
findIt = objects.find(str);
if ( findIt != objects.end() )
{
    return findIt->second;
}
else
{
   // Handle error here
}

正如其他人所指出的,您正在查找的名称在地图中不存在。每个人都很快建议您检查.find()的返回值。相反,我建议您不要拨打.find()。以下是我将如何解决您的问题:

Entity* RenderList::getByName(std::string str){
  return objects[str];
}

在上面的代码中,查找一个不存在的映射条目将创建一个指针值为NULL的条目,并返回NULL。

您需要在的某个地方添加一些代码来检查空指针,然后再对其进行尊重。