如何避免别名并提高性能?

时间:2015-07-24 02:17:07

标签: c++ c++11

在此Stack Overflow answer 证明了C ++中的别名会降低代码的速度。 C ++中的别名不仅适用于指针,也适用于引用,更常见的是these types specified by the standard。特别是,有

  

聚合或联合类型,其成员中包含上述类型之一(包括递归地,子聚合或包含联合的成员)

所以根据我的理解,如果我有如下代码,

 class A{
  public:
   int val;
 };

 void foo(vector<A> & array, int & size, A & a0) {
   for(int i=0;i<size;++i) {
    array[i].val = 2*a0.val;
   }
 }

a0可能会为array中的某个元素添加别名,也可能是别名size,因为上述引用,所以a0和{{1必须为每次迭代加载,导致性能下降。

  1. 然后我的问题是我应该怎么做代码以避免别名,并提高性能?
  2. 传递size无济于事,因为它不会避免标准规定的别名。按值传递const &?但这会复制我不喜欢的a0,因为在实践中,类a0可能非常复杂,复制是一个非常昂贵的选择。
  3. 是否有通用的解决方案来避免C ++中的别名?如果是,那是什么?

2 个答案:

答案 0 :(得分:7)

{+ 3}}似乎涵盖了避免C ++中的别名性能问题,而Evolution Working Group issue 72: N4150 Alias-Set Attributes: Toward restrict-like aliasing semantics for C++, N3988 Towards restrict-like aliasing semantics for C++ N3635 Towards restrict-like semantics for C++ 是该提案的最新版本。 EWG问题尚未解决,但显然已准备好进行审核。

该提案提出C类限制限定符,这些限定符目前由许多编译器在C ++中由扩展支持但具有模糊区域,该提案还说明了其他内容:

  

毫无疑问,限制限定符有益于编译器   在许多方面进行优化,特别是允许改进的代码运动和   消除负荷和商店。自推出C99以来   限制,它在许多编译器中作为C ++扩展提供。   但是这个特性在C ++中很脆弱,没有明确的C ++语法规则   和语义。现在随着C ++ 11的引入,仿函数正在出现   用lambdas替换,用户已经开始询问如何使用restrict   在lambdas面前。鉴于现有的编译器支持,我们   之前需要提供具有明确定义的C ++语义的解决方案   使用一些常见的C99限制子集变得广泛使用   与C ++ 11结构组合。

该提案还指出:

  

没有标准化和改进现有的C99   在C ++中限制设施,用户通常必须跳过相当多的环节来实现其效果   通过临时代码重写代码,或者分解和内联函数体来模拟其效果。

所以看起来目前还没有好的解决方案,虽然目前的编译器有扩展,提供C限制像语义,但有很多灰色区域 3。 C ++和C 中的限制问题涵盖了一些用于避免别名的方法,但它们都有缺陷。

该提案提到了N4150,其中提到了与这些技术相关的一些技术和缺陷。例如:

  

克服别名的最简单方法是复制   潜在的别名参数。

void rf2(type& output, const type& input) {
    type temp = input;
    output += ra1(temp);
    output += ra2(temp);
}
     

这种技术比简单技术更复杂,效率更低   按值传递参数。虽然这种技术在使用时很有用   处理遗留接口时,它不应该是主要技术。

此技术适用于您的情况。

注意有趣的别名和C99限制限定符N3538

答案 1 :(得分:1)

如果目的是在执行foo期间你不期望sizea0.val发生变化,那么你可以通过将这些变为本地值来明确表达:

void foo(vector<A> & array, int size, const A & a0) {
    auto new_val = 2*a0.val;
    for(int i=0;i<size;++i) {
        array[i].val = new_val;
    }
}

现在很明显,您打算将所有元素设置为相同的值。读者和编译器都很清楚。