使用指针会导致内存堵塞吗?

时间:2012-01-21 08:31:30

标签: c++ performance optimization memory-bandwidth

假设我在c++中有这种结构:

class A{
  public:
    B b;
}

class B{
  public:
    C c;
}

class C{
  public:
    double x;
    double y;
    double z;
    double s;
    function Usize(){
      s  = sqrt(pow(x,2) + pow(y,2) + pow(z,2));
    }
}

访问c中的值十次需要更多的内存流量,而不是创建一个直接指向c的指针并使用它吗?在代码术语中(假设合法值):

double dx = 2*rand()-1;
double dy = 2*rand()-1;
double dz = 2*rand()-1;

a->b->c.x *= dx;
a->b->c.y *= dy;
a->b->c.z *= dz;

if (a->b->c.x > 10) a->b->c.x -= 10;
else if (a->b->c.x <0) a->b->c.x += 10;
if (a->b->c.y > 10) a->b->c.y -= 10;
else if (a->b->c.y < 0) a->b->c.y += 10;
if (a->b->c.z > 10) a->b->c.z -= 10;
else if (a->b->c.z < 0) a->b->c.z += 10;

a->b->c->Usize();

VS

double dx = 2*rand()-1;
double dy = 2*rand()-1;
double dz = 2*rand()-1;


C* ac = a->b->c
ac.x *= dx;
ac.y *= dy;
ac.z *= dz;

if (ac.x > 10) ac.x -= 10;
else if (ac.x < 0)  ac.x += 10;
if (ac.y > 10) ac.y -= 10;
else if (Ac.y < 0) ac.y += 10;
if (ac.z > 10) ac.z -= 10;
else if (ac.z < 0) ac.z += 10;

感谢。

3 个答案:

答案 0 :(得分:11)

机会不是。没有区别。

虽然取消引用链接确实会导致更多内存访问,但现代编译器能够完全按照您的方式执行操作。 (也就是说,将你的第一个例子转换成你的第二个例子。)

这是由于标准编译器优化称为Common Subexpression Elimination(CSE)。

这个名字几乎说明了一切。在第一个示例中,a->b->c是将由编译器优化的公共子表达式。它只会被评估一次,保存结果,并重用于所需的所有实例。


有许多情况可能会阻止编译器进行此类优化。

  1. 如果声明了volatile任何相关变量,则不允许进行此优化,因为volatile变量要求每次使用时都重新加载。
  2. 如果(或可能)修改了任何相关变量,则不允许进行此优化,因为它可能会产生不同的结果。

  3. 作为旁注,你的第二个例子也更具可读性,因为有取消引用链接。
    所以如果我必须选择使用哪个,我还是会选择第二个例子。

答案 1 :(得分:2)

在这种情况下,一个好的编译器应该能够消除公共表达式并生成非常优化的代码。由于您正在访问基本类型,因此可以对a-&gt; b-&gt; c进行一次评估并在整个方法中使用。

调用C :: USize()或访问“C类”中的非基本类型将破坏此模式并迫使编译器重新评估下一行的a-&gt; b-&gt; c。

a->b->c.x = 10;
a->b->c.Usize();   // <-- Usize() may change a.b so the next line references another B.
a->b->c.y = 5;

这是因为编译器无法100%确定方法调用/运算符不会更改a,a.b或b.c,因此必须重新评估链以确保。

在这个阶段过早优化我几乎要担心这个问题。也就是说,你的第二个例子更具可读性,并且有助于编译器在以后插入任何方法调用时不必再猜测,所以我会去做。

答案 2 :(得分:1)

理论上它不会有所作为

任何现代优化器都应该转换为完全相同的代码。