当前位置: 首页 > 知识库问答 >
问题:

有没有办法直接在c中访问RTTI以改进虚拟调用中的分支预测?

查淮晨
2023-03-14

所以我正在创建一个库,它将有一个类一些基地{};这将由下游用户在许多类中派生。

class someBase {
  public:
    virtual void foo()=0;
};

我还有一个指向someBase的指针向量,我正在这样做:-

vector <someBase*> children;

// downstream user code populates children with some objects over here

for (i=0; i<children.size(); i++)
  children[i]->foo();

现在分析表明虚拟调用上的分支错误预测是我的代码中的(几个)瓶颈之一。我想做的是以某种方式访问对象的RTTI并使用它根据类类型对子向量进行排序,以改进指令缓存局部性和分支预测。

关于如何做到这一点有什么建议/解决方案吗?

要记住的主要挑战是:-

1.)我真的不知道哪些或多少类将从某个Base派生。假设,我可以在某个公共文件中有一个全局枚举,下游用户可以编辑该文件以添加他们自己的类类型,然后对其进行排序(基本上实现我自己的RTTI)。但这是一个丑陋的解决方案。

2.)皮奥特尼茨在下面的答案中建议使用type_info。但是,仅为此定义了 != 和 == 。关于如何在type_info上推导出严格的弱排序的任何想法?

3.)我真的希望改进分支预测和指令缓存位置,因此如果有替代解决方案,也将受到欢迎。

共有2个答案

钱星辰
2023-03-14

您可以在初始化中按类型对指针进行分类,例如:

std::vector<derivedA*> derivedA_list;
std::vector<derivedB*> derivedB_list;
//...

for (i=0; i<children.size(); i++)
    if (derivedA *d = dynamic_cast<derivedA*>(children[i]))
        derivedA_list.push_back(d);
    else if (derivedB *d = dynamic_cast<derivedB*>(children[i]))
        derivedB_list.push_back(d);
    //...

然后要调用该函数,您可以执行非虚拟调用:

for (i=0; i<derivedA.size(); ++i)
    derivedA_list[i]->derivedA::foo();
for (i=0; i<derivedB.size(); ++i)
    derivedB_list[i]->derivedB::foo();

还请注意,使用迭代器的循环可能会得到更好的优化。

方光华
2023-03-14

存在< code>typeid运算符。

您可以使用它来定义比较器,以便在矢量中对对象进行排序。

喜欢这个:

inline bool compareTypes(BaseClass* obj1, BaseClass* obj2)
{
   int compareRes = strcmp(typeid(*obj1).name(), typeid(*obj2).name());
   if (compareRes < 0) return true;
   if (compareRes > 0) return false;
   std::less<BaseClass*> ptrComp;
   return ptrComp(obj1, obj2); 
}

和:

  sort(v.begin(), v.end(), compareTypes);

[更新]

谢谢你告诉我,有一个函数是为这个目标设计的。它是<code>std::type_info::before(const type_info

inline bool compareTypes(A* obj1, A* obj2)
{
   return typeid(*obj1).before(typeid(*obj2));
}

我的早期版本不是那么糟糕;)它可用于需要对给定类的对象进行排序的情况。

 类似资料:
  • 问题内容: 我需要知道是否存在从子模块访问父模块的方法。如果我导入子模块: 我有-是否有一些Python魔术可以从中访问模块?上课与此类似。 问题答案: 如果您已经访问了模块,则通常可以从词典中访问它。Python不会使用名称保留“父指针”,特别是因为这种关系不是一对一的。例如,使用您的示例: 如果你会注意到存在的在模块只是一个假象在里面的语句。只要您需要该模块即可。 实际上,将来的版本可能不再导

  • 对于阵列,我们可以使用: 有没有类似的方法可以在一个步骤中初始化列表?

  • 是否有人设法让spring-data-neo4j在直接数据访问模式下使用Grails,如此处所述? 我无法让Grails尊重下面的@Autowired标记。下面的代码是spring在其文档中给出的示例的一个非常简单的版本: 我在执行grails run app时收到以下错误消息(这是一系列更长的嵌套异常,但这是主要原因): 创建在类路径资源[hello/TestGraph.class]中定义了名为

  • 有没有办法在“访问回调”函数中使用Drupal菜单的“页面参数”?我需要同时使用“访问参数”和“访问回调” “页面参数”= “访问参数”= “访问回调”= 在我的“访问回调”方法mymodule_application_page_access中,是否可以使用作为“页面参数”传递的值?

  • 当我点击任何编辑文本时,我想调整我的键盘。我在Android清单中使用windowSoftInputMode,但当我使用搜索编辑文本时,它覆盖了整个区域。键盘和底部布局覆盖整个区域

  • 我正在为一个系统建模,该系统有一个创建资源的操作和其他消耗该资源的操作。然而,一个给定的资源只能被消耗一次——有没有一种方法可以保证在编译时这样做? 具体来说,假设第一个操作烘焙蛋糕,还有另外两个操作,一个用于“选择吃”蛋糕,另一个用于“选择吃蛋糕”,我只能做其中一个。 通过在我们使用蛋糕后在蛋糕上设置一个标志,很容易在运行时强制执行不保留已经吃过的蛋糕(反之亦然)的限制。但是有没有办法在编译时强