优化器:用const对象替换const引用

时间:2015-12-20 13:22:52

标签: c++ optimization

Chandler Carruth在编译器优化talk中表示编译器在使用参考传递的参数优化函数方面很糟糕。我可以理解,当参数是非const引用时很难,因为编译器必须处理内存,或者参数的类型很复杂(一些奇怪的结构或类)。但是如果参数是const引用而内置类型真的有问题吗?优化程序可以用const float&替换const float吗?当启用SSE指令时,它会更有帮助,因为编译器可以正确地为它们对齐数据。

4 个答案:

答案 0 :(得分:13)

  

优化程序可以用const float&替换const float吗?

不,他们不能这样做,因为它可能会改变程序的语义。 const引用仍然是引用。它不能被价值取代。考虑这个例子:

void foo(const float& x, float a[]) {
    cout << x << endl;
    a[0] += 10.5;
    cout << x << endl;
}

int main() {
    float a[1] = { 3.25 };
    foo(a[0], a);
    return 0;
}

打印

3.25
13.75

Demo 1

如果您使用const float&更改const float,则结果为

3.25
3.25

Demo 2

这里的问题是a[0]x相同,但是连接是由调用者建立的,它在优化器的控制范围之外。

答案 1 :(得分:4)

我听了Youtube一段时间的谈话(痛苦)。

如果不了解函数实际执行的操作,则优化器无法替换引用。例如。

func.c:

 float func(const float& f)
 {
    return f * 2;
 }

main.c中:

 float complicated()
 {
     float f = 3.0;
     float f2 = func(f);
     f2 += 42 + f;
     return f2 / 17.0;
 }

 int main()
 {
    std::cout << complicated() << std::endl;
 }

因此,即使在f中没有修改复杂的func,编译器也不知道这一点。因此,必须将f作为参考传递,并func

如果函数是可内联的(因为它在同一个源中并且足够短),那么它确实可以内联函数并删除引用。但如果函数的源代码不同,则无法知道该函数的作用。

如果源不可用,编译器必须通过引用传递,因为它是函数的契约 - 参数以不同的方式传递给一件事,但即使不是这种情况[如同dasblinkenlight所示如果参数是引用,代码的含义可以改变。

答案 2 :(得分:3)

为什么不能进行这种替换的另一个原因是该函数实际上可以逐渐抛弃常量,然后改变变量,这将反映在调用范围中。如果传入的变量是const,那么这只是UB。那就是:

void f(const int & x) {
  const_cast<int &>(x) = 0;
}

int x = 1;
f(x);

是合法的并且符合您的期望。当然,这段代码很可怕,但仍然合法。将const引用更改为按值传递,您将更改程序,使编译器不符合要求。由于const_cast和它的使用范围有多广,编译器并没有真正使用const(局部变量除外);钱德勒在他的一次谈话中也提到了这一点。

答案 3 :(得分:2)

  

但是如果参数是const引用并且存在内置类型   真的有什么问题吗?

对于“复杂”或内置类型来说,引用“难以”进行优化并不是真的。问题是别名,由于其固有的性质,这是一个更糟糕的处理因为影响指针和引用的野兽。

  

优化器可以替换const float&amp;用const浮动?

@dasblinkenlight是一个非常好的例子,因为它会影响代码的可见行为,而优化器无法改变,因此无法进行优化。实际回归通常是sizeof (float&) > sizeof(float),因此您在技术上消耗了该参数的更多字节;虽然如此,但它实际上是无关紧要的,特别是如果在寄存器中传递的话。

对于那些有限的内存访问,在计数和副作用的可能性中,混叠不太可能是一个问题,或者仍然不值得采用技术来尝试优化它。