6

我想知道(除了明显的语法差异之外)在包含一个对象的多个实例(相同类型)的类或该类型的固定大小的对象数组之间是否会有任何效率差异。

在代码中:

struct A {
  double x;
  double y;
  double z;
};

struct B {
  double xvec[3];
};

实际上,我会使用 boost::arrays,它是 C 样式数组的更好的 C++ 替代品。

我主要关心的是构造/销毁和读/写这样的双精度,因为这些类的构造通常只是为了调用它们的成员函数之一。

感谢您的帮助/建议。

4

6 回答 6

8

通常,这两个结构的表示将完全相同。但是,如果您为自己的用例选择了错误的选项,则可能会导致性能不佳。

例如,如果您需要访问循环中的每个元素,您可以使用数组执行以下操作:

for (int i = 0; i < 3; i++)
    dosomething(xvec[i]);

但是,如果没有数组,您要么需要复制代码:

dosomething(x);
dosomething(y);
dosomething(z);

这意味着代码重复——这两种方式都可以。一方面循环代码更少;另一方面,非常紧凑的循环在现代处理器上可能会非常快,并且代码重复会破坏 I-cache。

另一个选项是开关:

for (int i = 0; i < 3; i++) {
    int *r;
    switch(i) {
        case 0: r = &x; break;
        case 1: r = &y; break;
        case 1: r = &z; break;
    }
    dosomething(*r); // assume this is some big inlined code
}

这避免了可能较大的 i-cache 占用空间,但会对性能产生巨大的负面影响。不要这样做。

另一方面,原则上,如果您的编译器不是很聪明,数组访问可能会更慢:

xvec[0] = xvec[1] + 1;
dosomething(xvec[1]);

由于 xvec[0] 和 xvec[1] 是不同的,原则上,编译器应该能够将 xvec[1] 的值保存在寄存器中,因此它不必在下一行重新加载该值。然而,有些编译器可能不够聪明,无法注意到 xvec[0] 和 xvec[1] 没有别名。在这种情况下,使用单独的字段可能会快一点。

简而言之,并不是在所有情况下都快。这是关于将表示与您使用它的方式相匹配。

就个人而言,我建议使用任何使在 xvec 上工作的代码最自然的方法。不值得花费大量时间来担心某些事情,充其量只会产生如此小的性能差异,以至于您只能在微基准测试中发现它。

于 2011-01-30T15:51:49.800 回答
5

MVC++ 2010 生成了完全相同的代码,用于从两个 POD 结构中读取/写入,就像在您的示例中一样。由于读/写的偏移量在编译时是可计算的,这并不奇怪。建设和破坏也是如此。

至于实际表现,一般规则适用:如果重要,则对其进行分析,如果不重要 - 为什么要关心?

对数组成员的索引对于结构的用户来说可能需要更多的工作,但话又说回来,他可以更轻松地遍历元素。

于 2011-01-30T15:42:59.557 回答
2

如果您无法决定并希望保留您的选择,您可以使用匿名联合:

struct Foo
{
    union
    {
        struct
        {
            double x;
            double y;
            double z;
        } xyz;
        double arr[3];
    };
};

int main()
{
    Foo a;
    a.xyz.x = 42;
    std::cout << a.arr[0] << std::endl;
}

一些编译器还支持匿名结构,在这种情况下,您可以忽略该xyz部分。

于 2011-01-30T16:57:07.753 回答
1

这取决于。例如,您给出的示例是支持“老式”数组的经典示例:数学点/向量(或矩阵)

  • 有固定数量的元素
  • 数据本身通常在对象中保持私有
  • 因为(如果?)它有一个类作为接口,你可以在构造函数中正确地初始化它们(否则,经典的数组初始化是我不太喜欢的,语法方面)

在这种情况下(使用数学向量/矩阵示例),我总是最终在内部使用 C 样式数组,因为您可以循环它们而不是为每个组件编写复制/粘贴代码。

但这是一个特例——对我来说,在现在的 C++ 中,数组 == STL 向量,它很快而且我不必担心 nuthin' :)

于 2011-01-30T15:24:56.520 回答
1

不同之处在于将变量存储在内存中。在第一个示例中,编译器可以添加填充以对齐数据。但在你的特殊情况下,这并不重要。

于 2011-01-30T19:14:46.857 回答
-1

原始数组提供了比 c++ 数组更好的缓存局部性,但是,如前所述,数组示例相对于多个对象的唯一优势是能够迭代元素。

真正的答案当然是创建一个测试用例并进行测量。

于 2011-01-30T15:25:10.693 回答