创建变量的本地别名是否会增加开销?

3
请考虑以下情况:
void func(const A& a)
{
    //Case 1:
    const int& val = a->b->c->d;
    func1(val);
    func2(val);

    //Case 2:
    func1(a->b->c->d);
    func2(a->b->c->d);

    //Case3:
    int val = a->b->c->d;
    func1(val);
    func2(val);
}

关于可读性,Case3是最直接的。

关于速度,在一个不错的编译器中,以上所有情况都相等吗?如果不是,哪些情况是最快和最慢的?

假设所有指针都是裸指针,并且它们指向堆中的对象。

更新:假设参数是一个const,如上所示,因此func1和func2可以通过值或const引用来获取参数。


3
值得注意的是,如果 func1 可以修改 aa->ba->b->c 和/或 a->b->c->d,那么这三个代码片段实际上可能是不等价的。因此,编译器将它们全部优化成相同的代码的唯一方法是,如果它可以访问 func1 的定义或以某种方式确认它们是功能等价的。 - ruakh
@ruakh 如果 func1 只传递了 d 的值,那么它如何修改 abc - Dave Rager
@Dave:也许 a 是一个全局变量。 - Ben Voigt
即使将a声明为const,编译器是否可以进行优化,或者仍然存在不同的线程修改a->b->c指向的可能性。因此,我猜测编译器不会对此进行优化。 - balki
https://gcc.godbolt.org/z/rJz0_l - balki
2个回答

1

假设这两个函数都采用值传递参数,情况3至少与情况1一样快,而情况1至少比情况2快。

正如ruakh在评论中提到的那样,在优化之前需要进行一些复杂的数据流分析。

如果函数参数是引用,则最终的内存加载可能永远不会发生。那么情况1将是最快的。

如果这些是宏而不是函数,那么一切都无法预测。


0
在第一个场景中,您在val中引用a->b->c->d,因此从编译器的角度来看,val是一个取消引用的指针。
就速度而言,第三个方法是最快的,因为它只是创建值的副本,然后使用该副本。
前两种方法的问题在于,您必须取消引用指针才能获取值,因此必须执行以下操作。
case 1
lea eax,[ebp+a]
push eax

case 2
lea eax, [ebp+a]
lea ebx, [eax]
....

case 3
mov eax [ebp+val]
push eax

你可以清楚地看到第三个是最快的


我明白了。但是如果d不是原始类型,case1或case2哪个更快? - balki
情况1比情况2更快。 - Ionut Hulub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接