使用 static_cast 处理混合(基础和派生)对象的向量是否存在性能风险?(又名 "it this a dumb idea?" )

Are there performance risks for using static_cast to deal with a vector of mixed (base & derived) objects? (aka "it this a dumb idea?")

本文关键字:idea 性能 存在 dumb it 是否 又名 this 处理 混合 cast      更新时间:2023-10-16

给定gameObject的基类和animatedGameObject的派生类,我认为将它们的所有实例存储在std::vector中可能会很好。如果向量GameObjects被声明为gameObject*的基类型,则派生的对象实例需要强制转换。

示例:

vector<gameObject*> GameObjects;
gameObject A* = new gameObject( ...init... ); 
animatedGameObject B* = new animatedGameObject( ...init... );
GameObjects.push_back(A);
GameObjects.push_back(B);
// to access the animatedGameObject functions:
static_cast<animatedGameObject*>(GameObjects[1])->functionUniqueToAnimated();

像往常一样害怕,我求助于Scott Meyers(有效C++,第三版),他写的主题是:

许多程序员认为,强制转换只会告诉编译器将一种类型视为另一种类型,但这是错误的。任何类型的类型转换(通过强制转换显式转换或通过编译器隐式转换)通常都会导致在运行时执行代码

我已经读了两遍他的第27项:最小化施法,但鉴于我对此缺乏经验,我很难回答一个简单的问题"这是一件愚蠢的事情吗?"

我应该提到的是,它之所以是一件愚蠢的事情,有几个原因与调用static_cast无关。按重要性排序的问题是:

  1. 在上面的例子中,我没有看到使用static_cast可能存在的风险吗
  2. 对于这种方法,是否有比std::vector更好的数据结构?(如果有一个是显而易见的,我不会要求你为我做研究。)

这是我第一次在这里提问,所以在必要的时候提前道歉。

static_cast不是适用于作业的工具,除非您知道指针指向的是animatedGameObject而不是gameObject。您使用什么数据结构来存储这些信息?

在基指针之后确定派生对象的类型是动态调度或dynamic_cast的工作。在您的示例中,调用GameObjects[1]->draw()应该不带强制转换,因为draw应该是一个虚拟函数。否则,您可以使用dynamic_cast< animatedGameObject & >( * GameObjects[1] )断言该对象是动画游戏对象,如果不是,则抛出std::bad_cast异常。(这仍然需要class gameObject中的virtual函数,通常是其析构函数。)

但对多态派生类型执行static_cast是一种代码气味。


此外,您还询问std::vector对于这个用例是否是一个好的数据结构。它是,但不是"裸"指针的矢量。C++11现在提供了"智能指针"内存管理类,它们为您执行newdelete,使实际运算符几乎过时。对于这种情况,请查看std::unique_ptr

  1. 若gameObjects[1]并没有动画化GameObject,应用程序(很可能)会惨死
  2. 如果draw()是gameObject中存在的虚拟方法,则不需要转换

通常,将基类强制转换为派生类是不安全的。在这些情况下,使用dynamic_cast是有意义的。如果无法执行转换,Dynamic_cast将返回NULL。

有比更好的数据结构吗

好吧,如果你的gameObjects没有在其他地方自动删除,那么使用std::vector<std::shared_ptr<gameObject> >之类的东西可能是有意义的。然而,标准共享指针可能会引入隐藏的开销(额外的新/删除,在最坏的情况下,如果它们被设计为线程安全的,它们甚至可能引入多线程互斥锁),所以你应该确保这些开销与你的目标兼容。