C++ 将类成员数组组合到单个数组时的性能损失

C++ 将类成员数组组合到单个数组时的性能损失,c++,arrays,performance,class,member,C++,Arrays,Performance,Class,Member,我试图让我的代码更快一点,我试图找出是否可以通过更好地管理存储在对象和东西中的数组来获得一些性能 因此,这背后的基本思想是,我倾向于为临时状态和永久状态保留单独的数组。这意味着它们必须一直单独索引,每次我想使用它们时,必须显式地写入正确的成员名称 这是具有此类数组的特定类的外观: class solution { public: //Costs float *cost_array; float *temp_cost_array; //Cost trend

我试图让我的代码更快一点,我试图找出是否可以通过更好地管理存储在对象和东西中的数组来获得一些性能

因此,这背后的基本思想是,我倾向于为临时状态和永久状态保留单独的数组。这意味着它们必须一直单独索引,每次我想使用它们时,必须显式地写入正确的成员名称

这是具有此类数组的特定类的外观:

class solution
{
public:

    //Costs
    float *cost_array;
    float *temp_cost_array;
    //Cost trend
    float *d_cost_array;
    float *temp_d_cost_array;

    ...

}
现在,由于我有一些函数/方法根据输入参数在临时状态或永久状态下工作,这些函数/方法如下所示:

void do_stuff(bool temp){
if (temp)
    work_on(this->temp_cost_array);
else
    work_on(this->cost_array);
}
void do_stuff(bool temp){
    work_on(this->cost_array[temp]);
}
这些都是这些分支的非常简单的例子。这些数组可以在代码中的各处单独索引。正是因为这些东西到处都是,我认为这是将所有东西结合起来的另一个原因,这样我也可以摆脱代码分支

所以我把我的班级改成:

class solution
{
public:

    //Costs
    float **cost_array;
    //Cost trend
    float **d_cost_array;
    ...

}
这些双数组的大小为2,每个元素都是float*数组。在程序开始时的对象创建过程中,这些对象只动态分配一次,并在程序结束时删除

因此,在这之后,我还将代码的所有临时分支转换为:

void do_stuff(bool temp){
if (temp)
    work_on(this->temp_cost_array);
else
    work_on(this->cost_array);
}
void do_stuff(bool temp){
    work_on(this->cost_array[temp]);
}
它看起来比以前优雅多了,但由于某种原因,性能比以前差了很多(几乎差了两倍),我真的不明白为什么会发生这种情况

所以,作为第一个洞察,我真的很想听听更有经验的人,如果我的代码优化背后的原理是有效的或无效的

访问每个数组所需的额外索引是否会对性能造成如此大的影响,从而克服所有if分支等问题?当然,这取决于整个过程的工作方式,但代码是一个野兽,我不知道如何正确地分析这一切

谢谢

编辑:

环境设置:
与2017年相比,在Windows 10上运行时,启用了全面优化(/Ox)

性能大幅下降的原因可能是由于我们引入了另一个间接级别的访问,这可能会大大降低程序的速度

更改之前的对象:

*array -> data[]
*temp_array -> data[]
**array -> * -> data[]
           * -> data[]
假设对象(即,
)在CPU缓存中,在更改之前,您有一个缓存未命中:从缓存中获取任意一个指针(缓存命中)并访问冷数据(缓存未命中)

更改后的对象:

*array -> data[]
*temp_array -> data[]
**array -> * -> data[]
           * -> data[]
现在我们必须访问指向数组的指针(缓存命中),然后索引冷数据(缓存未命中),然后访问冷数据(另一个缓存未命中)

当然,这是上面描述的最糟糕的情况,但也可能是这样

修复非常简单:使用
float*cost_array[2]
在对象中分配这些指针,而不是动态分配,即:

*array[2] -> data[]
          -> data[]

因此,在存储热和间接寻址级别中,这与更改之前的原始数据结构完全对应,其行为应该完全相同。

是否启用了优化?您使用的编译器标志是什么?@GregK。你是如何衡量绩效的?t看起来比以前优雅多了,但由于某种原因,绩效比以前差了很多(几乎是以前的两倍),我真的不明白为什么会发生这种情况。-您没有提到编译代码时使用的编译器和选项,例如使用的优化。其次,过度指针化代码并不一定会使代码更快——当您这样做时,会使编译器优化器感到困惑,从而可能会使您的代码比实际速度慢。因此,您的操作确实会导致调用新的临时对象及其关联的分配/解除分配?也许可以用float*数组来代替float**数组,试试float*数组[2]?你把分支预测完全排除在等式之外了,这有时是好的,但在这种情况下,可能预测器在大多数情况下都是正确的。