c – 懒惰构造 – 虚拟方法与if-then以存根吸气剂

我的问题的背景是我正在尝试创建一个惰性网格结构,其中网格的区域仅在需要时被实例化,否则它们在查询时返回默认值.

稍微解决问题,请考虑以下我的情况模型:

struct Container {
  std::vector<Base> data;

  float get(int indexOuter, int indexInner) {
     return data[indexOuter].get(indexInner);
  }
}

我想在某些情况下将Base :: get函数存根,以便始终返回相同的值,而在其他情况下,我想在某些数组中返回值.我想象两种可能的解决方案

第一个解决方案是在Base上使用一个标志,即

struct Base {
  std::vector<float> data;

  float get(int indexInner) {
    if (data.empty()) return 0;
    return data[indexInner];
  }
}

此解决方案将涉及在对象进入“存根模式”时销毁数据(调整大小为零),并在对象再次具体时重新创建数据.

我能想到的第二个解决方案是继承,即

struct Container {
  std::vector<Base*> data;

  float get(int indexOuter, int indexInner) {
     return data[indexOuter]->get(indexInner);
  }
}
struct Base {
  virtual float get(int indexInner) = 0;
}
struct Stub : public Base {
  float get(int indexInner) {
    return 0;
  }   
}
struct Concrete : public Base {
  std::vector<float> data;

  float get(int indexInner) {
    return data[indexInner];
  }   
}

然后在必要时在Container的数据数组中用Stub的实例替换Concrete的实例,反之亦然(注意确保干净的破坏).

问题是表现之一. Container :: get将被称为每秒1000次,也许更多.但是,进入/退出“存根模式”的基站的发生频率要低得多.

使用上面提出的两个解决方案,第一个解决方案涉及一个额外的if-then子句,而第二个解决方案涉及从Base指针到对象的间接,以及从抽象方法到派生实现的间接.

哪些解决方案能够提供最佳性能?我还没有考虑过其他更高性能的解决方案吗?

最佳答案 大多数现代处理器都不喜欢条件代码,特别是如果它不是“可预测的”(换句话说,您的数据有时会被填充,有时则不会.

跳过指向函数的指针通常比条件分支更快(考虑到你还需要检查它是否是存根[尽管你可以使用data.empty()来检查编译器很简单]).

因此,如果不对两种解决方案进行基准测试,我的猜测是虚拟Stub和Concrete会更快.但是,它将取决于用例.

Stub实现也将占用少量数据.另一方面,如果这是在std :: vector< Base *>中使用指针的唯一原因. data;,那么你可能想要考虑使用isStubbed(或data.empty())并使用std :: vector< Base>相反 – 整体保持间接水平 – 根据具体情况可以更好.

最终,如果它对性能很重要,那么您将需要实现两者,运行具有不同负载模式的基准测试,并测量时间.还要查看每个运行的分析数据,以了解代码花费时间的位置.

点赞