在循环中使用无变量多态类型进行优化
Optimization with unvariant polymorphic type inside a loop
我有一个昂贵的for
循环,由于循环内的动态转换开销,它花费的时间比应有的时间要多。
示例代码如下(可编译)
#include <iostream>
#include <memory>
struct Base {
virtual ~Base() {}
};
struct DerivedA : Base {};
struct DerivedB : Base {};
struct Calculator {
virtual void proceed(const DerivedA& ) const {
std::cout << "doing A stuff" << std::endl;
}
virtual void proceed(const DerivedB& ) const {
std::cout << "doing B stuff" << std::endl;
}
};
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
// "redundant" dynamic cast at every iteration
auto a_ptr = std::dynamic_pointer_cast<DerivedA>(base_ptr);
if(a_ptr) calc.proceed(*a_ptr);
auto b_ptr = std::dynamic_pointer_cast<DerivedB>(base_ptr);
if(b_ptr) calc.proceed(*b_ptr);
}
}
int main() {
std::shared_ptr<Base> base_ptr = std::make_shared<DerivedA>();
doStuff(base_ptr);
}
由于类在函数内部没有变化,我认为必须有一种方法来避免循环内部的多形开销(和分支),并执行单个动态强制转换和单个函数调用,而无需多次编写循环。
我考虑了什么:
- 在
proceed
调用内投射。 - 访客模式。
我不认为他们中的任何一个能解决问题。这些只是做同一件事的不同方式。
我正在考虑重新考虑我的设计,但在此之前,我很高兴听到您可能需要改进这段代码的任何想法和建议。
首先,我宁愿按照鲍德里克在对 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);
}
有时,如果您了解数据,则进行优化会有所帮助。
如果您知道您的数据主要包含类型 A,请确保这将是迭代的 if 列表中的第一个语句。不过,我不确定动态对象是否可以做到这一点。
也许您可以通过在迭代中使用 if-then-else 语句来排除一些要迭代的调用?是否真的有必要始终同时执行两个动态指针转换(a_ptr、b_ptr),或者是否有减少工作负载的异常?
这对你有帮助吗?
您可以枚举派生类的类型,从而避免双重调度 - 在Base
上实现一些GetClass()
作为纯虚拟
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);
}
相关文章:
- 通过switch和static_cast访问多态对象的运行时类型
- 当目标指针不是基类的类型时,为什么允许dynamic_cast为多态类生成 null 指针?
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- 如何使用静态多态性在 int 和指针类型之间进行转换?
- 如何调用指针类型的方法(禁用多态性)?
- 如何在不同类型的值之间进行选择以传递给多态函数?
- C++ 多态模板类,模板类型对象的实例化
- 如何多态地使用替代类型的 std::变体
- 对于多态类型T,如何在没有类型T实例的情况下获得指向T的虚拟表的指针
- 哈希多态类型的正确方式
- C++ 2D shared_ptr数组使用抽象多态类型初始化
- 一个类似 std::访问的函数,用于访问多态类型
- 有没有优雅的方法可以在多态 lambda 中编写类型别名
- 多态值类型和接口
- 将unique_ptr返回到多态类型
- 为什么删除的复制构造函数不允许使用其他具有多态类型的构造函数?
- 如何为多态性中的指定类型分配内存
- C 多态性:允许模棱两可的成员类型
- Sean Parent:对于继承层次结构中的多态类型,具有可变对象是极端的例外
- 通过指向非多态类型的基类的指针获取已分配内存的地址