指针容器的指针别名

Pointer aliasing of pointer containers

本文关键字:指针 别名      更新时间:2023-10-16

我了解到指针别名可能会影响性能,__restrict__属性(在GCC中,或其他实现中的等效属性(可能有助于跟踪哪些指针应该或不应该别名。同时,我还了解到GCC对valarray的实现存储了一个__restrict__’ed指针(https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.1/vallarray-source.html(,我认为这暗示了编译器(和负责的用户(,可以假设私有指针在valarray方法中的任何地方都没有别名。

但是,如果我们将指向valarray对象的指针别名,例如:

#include <valarray>
int main() {
    std::valarray<double> *a = new std::valarray<double>(10);
    std::valarray<double> *b = a;
    return 0;
}

a的成员指针也有别名是有效的吗?b的存在会损害valarray方法在其他方面可能受益的任何优化吗?(指向优化的指针容器是不是一种糟糕的做法?(

让我们首先了解混叠是如何影响优化的。

考虑一下这个代码,

void
process_data(float *in, float *out, float gain, int nsamps)
{
    int i;
    for (i = 0; i < nsamps; i++) {
        out[i] = in[i] * gain;
    }
}

在C或C++中,参数inout指向内存中的重叠区域是合法的。。。。当编译器优化函数时,它通常不知道inout是否是别名。因此必须假设通过CCD_ 13的任何存储都可以影响由CCD_,这严重限制了它对代码进行重新排序或并行化的能力(对于一些简单的情况,编译器可以分析整个程序,以确定两个指针不能是别名。但通常,编译器不可能确定两个指示器是否是别名,因此为了安全起见,它必须假设它们是别名(。


来到你的代码,

#include <valarray>
int main() {
    std::valarray<double> *a = new std::valarray<double>(10);
    std::valarray<double> *b = a;
    return 0;
}

由于CCD_ 15和CCD_。valarray使用的底层存储结构也会被别名化(我认为它使用了一个数组。对此不太确定(。因此,以类似于上面所示的方式使用ab的代码的任何部分都不会从编译器优化(如并行化和重新排序(中受益。请注意,仅仅是b的存在不会影响优化,而是影响您如何使用它。

学分:引用的部分和代码取自此处。这也应该是一个很好的来源,可以获得更多关于该主题的信息。

说a的成员指针也有别名是有效的吗?

是的。例如,a->[0]b->[0]引用相同的对象。这就是混叠。


b的存在会损害valarray方法在其他方面可能受益的任何优化吗?

没有。

您还没有在示例代码中对b做任何操作。假设您有一个比这个示例代码大得多的函数,它以相同的构造开始。如果该函数的前几行使用a但从不使用b,而其余几行则使用b但不使用a,则通常不会有问题。通常(不过,优化编译器确实会重新排列代码行。(

另一方面,如果混合使用ab,则不会影响优化。你正在做更糟糕的事情:你正在调用未定义的行为"不要这样做"是未定义行为问题的最佳解决方案。

附录

C restrict和gcc __restrict__关键字对编译器或标准库的开发人员没有约束。这些关键字是对编译器/库的承诺,即受限制的数据不会与其他数据重叠。编译器/库不会检查程序员是否违反了这一承诺。如果此承诺启用某些优化,而这些优化在数据重叠时可能无效,则编译器/库可以自由应用这些优化。

这意味着restrict(或__restrict__(是对您的限制,而不是编译器。即使没有b指针,也可以违反这些限制。例如,考虑

*a = a->[std::slice(a.size()-1,a.size(),-1)];

这是未定义的行为。