代码之家  ›  专栏  ›  技术社区  ›  David Holm

C++中的常数与编译器优化

  •  49
  • David Holm  · 技术社区  · 17 年前

    12 回复  |  直到 17 年前
        1
  •  56
  •   Luc Touraille    17 年前

    我认为const关键字主要用于程序语义的编译检查,而不是优化。

    GotW #81 article ,很好地解释了为什么编译器在通过const引用传递参数或声明const返回值时无法优化任何内容。原因是编译器无法确保引用的对象不会被更改,即使声明了const:可以使用const_cast,或者其他一些代码可以在同一对象上具有非const引用。

    然而,引用赫伯·萨特的文章:

    有[只有]一种情况是 也就是说,对象被设置为常量 定义它们的点。因为 在这种情况下,编译器通常可以 成功地把这样的“真的常量”

    这篇文章还有很多内容,所以我鼓励您阅读:在这之后,您将对不断优化有更好的理解。

        2
  •  35
  •   Michael Burr    17 年前

    让我们忽略方法,只看常量对象;编译器在这里有更多的优化机会。如果对象被声明为常量,则(ISO/IEC 14882:2003 7.1.5.1(4)):

    除非任何类成员声明 可变(7.1.1)可以修改,任何 尝试修改常量对象 在其使用寿命期间(3.8)会导致 未定义的行为。

    让我们忽略可能具有可变成员的对象-编译器可以自由地假设对象不会被修改,因此它可以产生显著的优化。这些优化可以包括以下内容:

    • 完全消除永远无法到达的代码,因为const对象用于编译时已知的条件表达式中

    请注意,只有当实际对象是常量时,这一点才适用-它不适用于通过常量指针或引用访问的对象,因为这些访问路径可能导致对象不是常量(甚至可以通过常量指针/引用来更改对象,只要实际对象是非常量的,并且您抛弃了对象访问路径的常量)。

    这些物品的使用。

        3
  •  6
  •   Paul Nathan    17 年前

    手淫开始了

    端部手动切割

        4
  •  5
  •   Mike F Mike F    17 年前

    无聊的。常量正确性与其说是优化,不如说是样式/错误检查。一个完全优化的编译器将跟踪变量的使用情况,并且可以检测变量是否有效常量。

    是的,const正确性是一个值得追求的目标,但它不会告诉编译器任何它自己无法理解的东西,假设一个好的优化编译器。

        5
  •  3
  •   James Curran    17 年前

    它不会优化声明为const的函数。

    它可以优化 呼叫

    void someType::somefunc();
    
    void MyFunc()
    {
        someType A(4);   // 
        Fling(A.m_val);
        A.someFunc();
        Flong(A.m_val);
    }
    

    要调用Fling,必须将值A.mval加载到CPU寄存器中。如果someFunc()不是常量,则必须在调用Flong()之前重新加载该值。如果someFunc是const,那么我们可以使用仍然在寄存器中的值调用Flong。

        6
  •  3
  •   Andrew Stein    17 年前

    拥有的主要原因 因为const是为了const的正确性,而不是为了方法本身可能的编译优化。

    如果 它们(理论上)是可以优化的。但编译器只能看到范围。毕竟,编译器必须允许使用const_cast在别处修改它们。

        7
  •  2
  •   Mike Dunlavey    17 年前

    这些都是正确的答案,但答案和问题似乎假定了一件事:编译器优化实际上很重要。

    编译器优化只涉及一种代码,那就是

    • 紧密的内环,
    • 在您编译的代码中,与第三方库不同,
    • 程序计数器花费其时间的一小部分

        8
  •  1
  •   Rob Walker    17 年前

    如果优化器真的在const声明中投入了大量资源,我会感到惊讶。有很多代码最终将抛出const ness,这将是一个非常鲁莽的优化器,它依赖程序员声明来假设状态何时可能发生变化。

        9
  •  1
  •   David Thornley    17 年前

        10
  •  0
  •   Konrad Rudolph    17 年前

    最明显的一点是 const 直接优化是将参数传递给函数。确保函数不修改数据通常很重要,因此函数签名的唯一真正选择是:

    void f(Type dont_modify); // or
    void f(Type const& dont_modify);
    

    当然,这里真正的魔法是传递引用,而不是创建对象的(昂贵的)副本。但是如果引用没有标记为 常数 ,这将削弱此函数的语义,并产生负面影响(例如使错误跟踪更加困难)。因此 常数

    /编辑:事实上,一个好的编译器可以分析函数的控制流,确定它不修改参数,并自行进行优化(传递引用而不是副本)。 这里只是对编译器的一个帮助。然而,由于C++具有一些相当复杂的语义,这样的控制流分析对于大型函数来说可能非常昂贵,因此我们不应该依赖编译器。有人有任何数据支持我/证明我错了吗?

    /EDIT2:是的,一旦自定义副本构造函数发挥作用,它就变得更加棘手,因为不幸的是,编译器在这种情况下不允许忽略调用它们。

        11
  •  0
  •   Tim Cooper    14 年前

    这个代码,

    class Test
    {
    public:
      Test (int value) : m_value (value)
      {
      }
    
      void SetValue (int value) const
      {
        const_cast <Test&>(*this).MySetValue (value);
      }
    
      int Value () const
      {
        return m_value;
      }
    
    private:
      void MySetValue (int value)
      {
        m_value = value;
      }
    
      int
        m_value;
    };
    
    void modify (const Test &test, int value) 
    {
      test.SetValue (value);
    }
    
    void main ()
    {
      const Test
        test (100);
    
      cout << test.Value () << endl;
      modify (test, 50);
      cout << test.Value () << endl;
    }
    

    产出:

    100
    50
    

    这意味着const声明的对象已在const成员函数中更改。在C++语言中存在conTySCAST(和可变关键字)意味着const关键字不能帮助编译器生成优化代码。正如我在之前的文章中指出的,它甚至可以产生意想不到的结果。

    常数!=优化

    事实上,这是一个合法的C++修改器:

    volatile const
    
        12
  •  -1
  •   Tim Cooper    14 年前

    const 帮助编译器优化主要是因为它使您编写可优化的代码。除非你投进去 const_cast .