【问题标题】:How to avoid dynamic cast in polymorphism with derived class of template type如何使用模板类型的派生类避免多态性中的动态强制转换
【发布时间】:2017-03-31 19:20:28
【问题描述】:

我有这个架构(简称):

class BaseBatch {
    virtual ~BaseBatch(){};
};

template<class T>
class Batch : public BaseBatch
{

    void draw(T* data) {
       do something..
    }
};

class BatchManager
{
private:
   static std::vector<BaseBatch*> batches;
public:

    template <class T>
    static void placeData(T* data){

        //Loop through the entire container
        bool found = false;
        for (auto&& b: batches())
            if (b->get_type() == typeid(T)) {

                dynamic_cast<Batch<T>*>(b)->draw(data);
                found = true;
            }

        //If no bach found, create a new One
        if (not found) {
            batches.push_back(new Batch<T>);
        }
    }
};

问题是 placeData 函数在 1 个循环中被多次调用,我认为动态转换对性能来说是一个真正的痛苦,但不知道如何在不使用它的情况下解决这个问题。真的有那么大的问题还是我不​​应该打扰它并继续使用它?如果我应该避免它,你会建议什么?谢谢

【问题讨论】:

  • 这个设计对我来说看起来很奇怪 - 你不能只用std::vector&lt;Batch*&gt; 代替吗? (或除另一个之外) - 特别是因为 dynamic_cast&lt;Batch&lt;T&gt;*&gt;(b)-&gt;draw(data); 可能导致 UB(因为 dynamc_cast 可能会返回 nullptr 如果它无法执行演员表)
  • BaseBatch 中的draw 声明为纯虚拟。
  • 您“认为”这是性能问题吗?这还不够好。您需要测量,并且需要使用分析器来查看实际 性能问题在哪里。它可能(也可能不是)在您期望的地方;这些事情很棘手;总是测量。
  • @UnholySheep 我不能,因为 Batch 是一个模板类,所以在初始化它之前需要知道一个参数
  • @JesperJuhl 你可能是对的,没有措施我不能 100% 确定,但我想避免动态投射,我只是不喜欢它,直到现在我一直在躲避它成功

标签: c++ templates inheritance polymorphism


【解决方案1】:

不要使用std::vector&lt;Batch*&gt;,而是使用std::unordered_map&lt;std::type_index, std::unique_ptr&lt;BaseBatch&gt;&gt;。要访问批处理,请使用batches.find(std::type_index(typeid(T))),然后将static_cast 使用Batch&lt;T&gt;*static_cast 没有运行时开销。要创建新批次,请使用 std::type_index(typeid(T)) 作为键。

dynamic_cast 的性能可能不是这里的问题。事实上,使用此解决方案调用typeid 可能与dynamic_cast 一样糟糕。真正的潜在收益是unordered_map 的查找速度与遍历谁知道如何大的vector 的每个元素并尝试dynamic_cast 相比。

【讨论】:

  • 如果不实际测量性能,您无法说它会更快。不要只是猜测(或使用以前的经验) - 总是衡量。
  • @JesperJuhl 是的,我愿意。因为遍历向量中的 n 个项目,尝试对每个项目进行动态转换肯定比 O(1) 查找无序映射更糟糕,如果 n 很大的话。
  • 我知道。我不是一个完全的白痴。但是,编译器经常以令人惊讶的方式优化并且总是需要(遵循科学方法)测量结果,这仍然是一个事实。
  • @JesperJuhl 我没有测量这些家伙的代码。他可以衡量他当前的解决方案并与我提出的解决方案进行比较。当有一个很好的答案可能会改善情况并会帮助未来与这个人有类似设置的人时,用“Go measure better, I don't believe you”回答每一个优化问题是 100% 适得其反.
  • 不客气;这不应该是一场战斗 :-) 我只是想说明一点——过去不测量已经咬了我很多次。人们经常会对编译器优化的内容和时间感到惊讶。
猜你喜欢
  • 1970-01-01
  • 2014-11-26
  • 1970-01-01
  • 2021-02-28
  • 2020-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-21
相关资源
最近更新 更多