C++ 循环内具有不变多态类型的优化

C++ 循环内具有不变多态类型的优化,c++,dynamic,c++11,dynamic-cast,dynamic-dispatch,C++,Dynamic,C++11,Dynamic Cast,Dynamic Dispatch,我有一个昂贵的for循环,由于循环内部的动态转换开销,它花费的时间比它应该花费的时间要多 示例代码如下(可编译) #包括 #包括 结构基{ 虚拟~Base(){} }; struct-DerivedA:Base{}; struct-DerivedB:Base{}; 结构计算器{ 虚拟无效继续(const DerivedA&)const{ std::cout有时,如果您了解数据,优化会有所帮助 如果您知道您的数据主要包含类型A,那么请确保这将是迭代的If列表中的第一条语句 也许您可以通过在迭代中使

我有一个昂贵的
for
循环,由于循环内部的动态转换开销,它花费的时间比它应该花费的时间要多

示例代码如下(可编译)

#包括
#包括
结构基{
虚拟~Base(){}
};
struct-DerivedA:Base{};
struct-DerivedB:Base{};
结构计算器{
虚拟无效继续(const DerivedA&)const{

std::cout有时,如果您了解数据,优化会有所帮助

如果您知道您的数据主要包含类型A,那么请确保这将是迭代的If列表中的第一条语句

也许您可以通过在迭代中使用if-then-else语句排除一些要迭代的调用?是否真的需要始终同时执行动态指针强制转换(a_ptr、b_ptr),或者是否存在减少工作负载的异常


这对你有帮助吗?

首先,我宁愿按照鲍德里克在对OP的评论中的建议去做,然后我会尝试OP中引用的其他备选方案。每次我都会分析/测量结果,以做出明智的决定

如果您还不满意,那么我建议您做以下几点:

template <typename T>
void doStuffImpl(const T &obj) {
    Calculator calc;
    for(int i = 0; i < 1000000; i++)
        calc.proceed(obj);
}

void doStuff(const std::shared_ptr<Base> &base_ptr) {

    auto a_ptr = std::dynamic_pointer_cast<DerivedA>(base_ptr);
    if (a_ptr)
        doStuffImpl(*a_ptr);

    auto b_ptr = std::dynamic_pointer_cast<DerivedB>(base_ptr);
    if (b_ptr)
        doStuffImpl(*b_ptr);
}
模板
无效文件(施工图和obj){
计算器计算器;
对于(int i=0;i<1000000;i++)
计算程序(obj);
}
无效剂量(常数标准::共享剂量和基础剂量){
自动a_ptr=std::动态指针转换(基本ptr);
如果(a_ptr)
dostuffinpl(*a_ptr);
自动b_ptr=std::动态指针转换(基本ptr);
如果(b_ptr)
dostuffinpl(*b_ptr);
}

您可以枚举派生类的类型,从而避免双重分派-将一些
GetClass()
实现为
Base上的纯虚拟类

void doStuff(const std::shared_ptr<Base> &base_ptr) {
Calculator calc;
// Code that does stuff using only Base properties
for(int i = 0; i < 1000000; i++) { // expensive loop

  switch(base_ptr->GetClass())
  {
    case TYPE_A:
    // "redundant" dynamic cast at every iteration
    auto a_ptr = std::dynamic_pointer_cast<DerivedA>(base_ptr);
    if(a_ptr) 
      calc.proceed(*a_ptr);
    break;

    case TYPE_B:
    auto b_ptr = std::dynamic_pointer_cast<DerivedB>(base_ptr);
    if(b_ptr)
      calc.proceed(*b_ptr);
    break;
  }
}

int main() {
  std::shared_ptr<Base> base_ptr = std::make_shared<DerivedA>();
  doStuff(base_ptr);
}
void doStuff(const std::shared_ptr&base_ptr){
计算器计算器;
//只使用基本属性进行填充的代码
对于(int i=0;i<1000000;i++){//昂贵的循环
开关(base_ptr->GetClass())
{
案例类型_A:
//在每次迭代中进行“冗余”动态强制转换
自动a_ptr=std::动态指针转换(基本ptr);
如果(a_ptr)
继续计算(*a_ptr);
打破
案例类型_B:
自动b_ptr=std::动态指针转换(基本ptr);
如果(b_ptr)
计算继续(*b_ptr);
打破
}
}
int main(){
std::shared_ptr base_ptr=std::make_shared();
doStuff(基本要求);
}

是否有理由不在基础上使用抽象的继续方法,并在两个派生类中以不同的方式实现它?这样就不需要显式的动态强制转换-它只是一个普通的vtable查找。@MFontani使用双重分派有什么好处?我看不到它们。@FKaria nevermind。我的重点是设计GN,而不是可能的优化。@ BaldRek是的,我意识到多态性已经以另一种方式实现了。这就是我现在正在考虑做的。在我想问其他想法之前。@ FKaria:我想在你的情况下,“标准C++多态性”(如上所述)。可能是最好的方法。您还可以让
dostuffinpl
获取一个指针(可能为空),直接传递
dynamic\u pointer\u cast
的结果,而不使用临时变量(稍微整洁一点)谢谢。我开始考虑用模板做些什么,我没能弄清楚一些东西。我会尝试C++的标准多态性,然后也许是这个。我现在就可以看到所有可能性。
void doStuff(const std::shared_ptr<Base> &base_ptr) {
Calculator calc;
// Code that does stuff using only Base properties
for(int i = 0; i < 1000000; i++) { // expensive loop

  switch(base_ptr->GetClass())
  {
    case TYPE_A:
    // "redundant" dynamic cast at every iteration
    auto a_ptr = std::dynamic_pointer_cast<DerivedA>(base_ptr);
    if(a_ptr) 
      calc.proceed(*a_ptr);
    break;

    case TYPE_B:
    auto b_ptr = std::dynamic_pointer_cast<DerivedB>(base_ptr);
    if(b_ptr)
      calc.proceed(*b_ptr);
    break;
  }
}

int main() {
  std::shared_ptr<Base> base_ptr = std::make_shared<DerivedA>();
  doStuff(base_ptr);
}