我了解到指针别名可能会影响性能,并且__restrict__
属性(在GCC中,或其他实现中的等效属性)可能有助于跟踪哪些指针应该或不应该别名。同时,我还了解到GCC的valarray
实现存储了一个__restrict__
'ed指针({3}}中的第517行),我认为暗示了编译器(和负责用户)的私有指针可以假设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
方法可能带来的任何优化? (指向优化的指针容器是不好的做法吗?)
答案 0 :(得分:1)
让我们首先了解如何别名会损害优化。
考虑这段代码,
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 ++中,参数
in
和out
指向内存中的重叠区域是合法的....当编译器优化函数时,通常不知道是否in
和out
是别名。因此,必须假设通过out
的任何商店都会影响in
指向的内存,严重限制了它重新排序或并行化代码的能力(对于一些简单的情况,编译器可以分析整个程序)确定两个指针不能是别名。但一般来说,编译器不可能确定两个指针是否是别名,所以为了安全起见,它必须假定它们是。)
来到你的代码,
#include <valarray>
int main() {
std::valarray<double> *a = new std::valarray<double>(10);
std::valarray<double> *b = a;
return 0;
}
由于a
和b
是别名。 valarray
使用的底层存储结构也会有别名(我认为它使用了一个数组。对此不太确定)。因此,以类似于上面所示的方式使用a
和b
的代码的任何部分都不会受益于编译器优化,例如并行化和重新排序。请注意,b
的存在不会影响优化,但会如何使用它。
现金: 引用的部分和代码来自here。这也可以作为有关该主题的更多信息的良好来源。
答案 1 :(得分:0)
是否可以说a的成员指针也是别名?
是。例如,a->[0]
和b->[0]
引用相同的对象。那个别名。
b的存在是否会损害valarray方法可能带来的任何优化?
没有
您尚未在示例代码中使用b
完成任何操作。假设您的函数比以相同构造开头的示例代码大得多。如果该函数的前几行使用a
但从不b
,则通常没有问题,其余行使用b
但从不使用a
。通常。 (然而,优化编译器会重新排列代码行。)
另一方面,如果您将a
和b
混合使用,则不会对优化造成影响。你正在做更糟糕的事情:你正在调用未定义的行为。 &#34;不要这样做&#34;是未定义行为问题的最佳解决方案。
<强>附录强>
C restrict
和gcc __restrict__
关键字不是对编译器或标准库的开发人员的约束。这些关键字是编译器/库的承诺,限制数据不会与其他数据重叠。编译器/库没有检查程序员是否违反了这个承诺。如果此承诺启用某些可能因重叠数据而无效的优化,则编译器/库可以自由应用这些优化。
这意味着restrict
(或__restrict__
)是对您的限制,而不是编译器。即使没有b
指针,您也可以违反这些限制。例如,考虑
*a = a->[std::slice(a.size()-1,a.size(),-1)];
这是未定义的行为。