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);
}