【问题标题】:Downcasting pointers向下转换指针
【发布时间】:2016-05-12 13:20:45
【问题描述】:

基本上,我有两个类,Spatial 和 Node,继承自 IEntity; IEntity 是一个抽象类(接口)。我将实体 object pointers 存储在 SceneGraph 类的 std::vector 中,例如 std::vector<IEntity*> 所以为了区分 Spatials 和 Nodes,我首先有了这样做的想法

if(!dynamic_cast<Node*>(myEntity)) // equals nullptr, cast failed
{
  BOOST_LOG_TRIVIAL(info) << "It is a node !";
}

但是这段代码将用于高性能引擎,我无法在一秒钟内承受数千/数百万次动态转换调用;那么,您建议如何区分空间指针和节点以向下转换而不会出现任何错误(以最快的方式)? PS。我知道不建议将指针存储在 stl 容器中,但这是围绕 imo 的最佳方式。

【问题讨论】:

  • 这取决于你想如何处理向下转换的对象?
  • 好吧,在场景图中,我需要区分节点实体和空间实体(基本上是网格)以:解析节点或渲染空间(节点包含其他实体;它们基本上是数组,带有额外的变换组件)
  • 是否可以将动作抽象为IEntity中的虚函数?然后你可以在SpatialNode 中覆盖它。
  • 你的意思是像一个虚函数 IsNode() ?这两个类之间唯一的共同点是它们是实体并且有一个变换组件。但由于我的 API 设计,它们需要存储在一起
  • @Coder32 您是否认为这可能表明 API 设计存在缺陷?

标签: c++ c++11


【解决方案1】:

首先,在这种情况下不得不沮丧显然是糟糕的设计违反了 Liskov 原则的迹象。要在 OOP 域中修复它,而不是向下转换,您应该为每个 IEntity 对象调用某个虚拟函数,然后对 NodeSpatial 执行不同的操作。

其次,如果您以性能为目标,您应该在性能关键代码中放弃 OOP。 IE。不调用虚函数。您还应该尝试尽可能多地利用内存缓存,因为对非缓存数据的内存访问通常是大多数性能关键代码的瓶颈。怎么做? Google 用于“数据驱动设计”或“面向数据的编程”。这通常使用称为“实体组件系统”的东西来实现,通常在计算机游戏中。在您的情况下,您可能需要将您的NodesSpatials 分隔在单独的向量中,而不是通过引用或指向IEntity 的指针,而是通过值(使用vector&lt;Node&gt;vector&lt;Spatial&gt; 而不是vector&lt;IEntity*&gt;)和然后线性或以可预测/有规律的顺序遍历它(有利于专业数据预取)。这将为您提供可以达到的最快速度。并且可能只有在那之后你才应该从一些算法微调开始......这是典型的场景,所以我认为这也是你的情况。

顺便说一句。除了性能(如您的情况)外,将指针存储在 STL 容器中没有任何问题。或者有吗?

更新:正如您在下面提到的,出于某些算法原因,您可能需要将对象保留在树结构中。在这种情况下,我关于按值将对象保存在容器中的建议可能不是那么有用或难以实现。无论如何,在任何情况下,您都必须首先分析我们的代码,然后尝试优化和摆弄缓存等。但是,我关于需要向下转换表明的糟糕设计的第一个注释仍然有效。 :)

【讨论】:

  • 我曾经读过一篇关于去书的文章,因为如果指针被删除,它会导致未定义的行为。无论如何,问题是我不能在两个不同的数组中存储节点和空间:你可能有这样的情况http://imgur.com/W2RizCb
  • 在 STL 容器中存储裸指针的一个普遍问题当然是清理。但如果这些是“非拥有”指针,则清理取决于程序的其他部分。
  • Erik:是的,清理是唯一的问题,但它很容易管理。例如。使用智能指针(unique_ptr 优先于 shared_ptr)或清理自己。这很简单,我不会称之为问题。 :)
  • 顺便说一句,我也对我的opengl对象使用这种清理方法;它们的访问方式类似于 std::shared_ptr object = CreateShaderProgram(args)
  • 根据您提供的链接,您似乎希望将数据保存在树结构中。那么,这取决于您希望如何在代码的性能关键部分中遍历它。线性遍历总是最适合缓存,但我猜你想使用树,因为你需要它来做一些聪明的算法。还是因为所有权具有树状结构,所以存在三个?
猜你喜欢
  • 2022-01-18
  • 1970-01-01
  • 2012-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-29
  • 1970-01-01
相关资源
最近更新 更多