我已经阅读了关于C ++中const-correctness的所有建议,并且它(部分)很重要,因为它有助于编译器优化代码。 我从未见过的是关于编译器如何使用这些信息来优化代码的一个很好的解释,甚至连好书都没有解释幕后发生的事情。

例如,编译器如何优化声明为const的方法与不应该但应该是的方法。 当你引入可变变量时会发生什么? 它们会影响const方法的这些优化吗?

===============>>#1 票数:54

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

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

然而,引用Herb Sutter的文章:

只有一种情况说“const”可以真正意味着某种东西,那就是当对象在它们被定义的点被制成const时。 在这种情况下,编译器通常可以成功地将这种“真正的const”对象放入只读存储器中[...]。

本文还有很多内容,所以我鼓励您阅读它:在此之后您将更好地理解持续优化。

===============>>#2 票数:35 已采纳

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

除了可以修改声明为mutable(7.1.1)的任何类成员之外,任何在其生命周期内修改const对象的尝试(3.8)都会导致未定义的行为。

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

  • 将对象的值直接合并到机器指令操作码中
  • 完全消除永远无法访问的代码,因为const对象用于编译时已知的条件表达式
  • 如果const对象控制循环的迭代次数,则循环展开

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

在实践中,我认为没有编译器可以对各种const对象执行任何重要的优化。 但对于原始类型的对象(整数,字符等),我认为编译器可以非常积极地优化这些项的使用。

===============>>#3 票数:6

handwaving开始

本质上,数据修复得越早,编译器就可以越多地绕数据的实际分配移动,确保管道不会停顿

结束了

===============>>#4 票数:5

咩。 正确性更像是一种样式/错误检查,而不是优化。 完全优化的编译器将遵循变量使用,并且可以检测变量何时是否有效。

除此之外,编译器不能依赖于你说实话 - 你可能会丢弃它不知道的库函数中的const。

所以,是的,const-correctness是一个值得瞄准的东西,但它并没有告诉编译器任何它不会为自己弄清楚,假设一个好的优化编译器。

===============>>#5 票数:3

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

它可以优化调用声明为const的函数的函数。

void someType::somefunc();

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

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

===============>>#6 票数:3

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

如果变量是常数,它们(理论上)可以被优化掉。 但只有编译器可以看到范围。 毕竟编译器必须允许在其他地方使用const_cast修改它们。

===============>>#7 票数:2

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

编译器优化只有一种代码,即代码中的代码

  • 一个紧密的内环,
  • 在您编译的代码中,而不是第三方库,
  • 不包含函数或方法调用(甚至是隐藏的函数),
  • 程序计数器花费了大量时间

如果其他99%的代码被优化到N度,它就不会产生差异,因为它只在程序计数器实际花费时间的代码中很重要(可以通过采样找到)。

===============>>#8 票数:1

如果优化器实际上将大量库存放入const声明中,我会感到惊讶。 有很多代码最终会抛弃const-ness,它将是一个非常鲁莽的优化器,它依赖于程序员声明来假设状态可能发生变化。

===============>>#9 票数:1

const-correctness也可用作文档。 如果函数或参数被列为const,我不需要担心从我的代码下面更改的值(除非团队中的其他人非常顽皮)。 不过,如果它没有内置到库中,我不确定它是否真的值得。

===============>>#10 票数:0

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

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

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

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

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

===============>>#11 票数:0

这段代码,

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 ++语言中const_cast(和mutable关键字)的存在意味着const关键字无法帮助编译器生成优化代码。 正如我在之前的帖子中指出的那样,它甚至可以产生意想不到的结果。

作为基本规则:

const!=优化

实际上,这是一个合法的C ++修饰符:

volatile const

===============>>#12 票数:-1

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

  ask by David Holm translate from so

未解决问题?本站智能推荐:

1回复

不是编译器优化C ++中的代码部分

有没有办法告诉编译器不优化代码的选择部分? 我知道你可以告诉编译器不要使用volatile来优化某些变量但是整个代码块呢?
3回复

C / C ++编译器反馈优化

有没有人看到使用C / C ++编译器提供的反馈优化来支持分支预测,缓存预加载等功能的不同程序的任何实际数字。 我搜索了它,令人惊讶的是,即使是流行的翻译开发小组似乎都没有检查过这种效果。 并且将ruby,python,php等性能提高10%左右应该被认为是有用的。 真的没有任何好
7回复

C / C ++编译器会优化此if语句吗?

我有这样的代码,我觉得很难读: 我只是将其更改为以下内容,以使其更具可读性: 但是我现在应该关注效率吗? 我的意思是,在code1 ,如果第一个连接子句得到满足,那么即使看第二个连接子句也不会费心,因为已经很清楚该语句是正确的。 但是在我更具可读性的示例中,必须同时计
1回复

C ++编译器或链接器优化

我正在尝试使用类映射创建一个自动加载类系统,如本文最佳回答: 有没有办法从持有类名的字符串中实例化对象? 所以我根据自己的需要创建了这段代码: 当然我已经在foo类和foo.cpp文件底部定义了REGISTER_DEC_TYPE我放了:REGISTER_DEF_TYPE(fo
7回复

c ++:编译器能否优化此代码段?

对于外循环的每次执行,都检查“常量”的值。 但是,常量永远不会改变,所以浪费了大量的CPU时间来测试条件常数<10? 一遍又一遍地。 人类会在前几次传球后意识到常数永远不变,并且智能地避免一遍又一遍地检查它。 编译器是否注意到这一点并对其进行智能优化,或者重复if循环是否不可避免
7回复

C ++编译器可以优化“for”循环中的“if”语句吗?

考虑一个像这样的例子: 如果for循环中的flag没有改变,那么它在语义上应该等同于: 仅在第一种情况下,代码可能会更长(例如,如果使用了几个for循环,或者do_something()是一个与do_something_else()大致相同的代码块),而在第二种情况下,标记会被检
6回复

C ++:编译器优化和变量; 远?

在C ++中,这样的语句是有效的: IMO它没有任何意义,所以我的问题是,如果你这样做,它会以任何方式影响编译结果,还是编译器会优化它? 谢谢!
4回复

我的C ++编译器是否优化了我的代码?

在使用现代C ++编译器(包括MSVC,GCC,ICC)时,我怎么说它是否有: 并行化代码 矢量化循环(或使用其他特定的处理器指令) 展开循环 检测到尾递归 执行RVO(返回值优化) 或以其他方式优化 没有深入编译器产生的汇编代码?
5回复

传递参数的C ++编译器优化

我正在使用一个可以在运行时启用/禁用报告的日志记录模块。 电话通常类似于: 我正在使用WARN的内联函数,但我很好奇在幕后进行了多少优化 - 在整个程序中对参数的评估将是昂贵的。 WARN函数是这样的: 鉴于构造字符串参数没有副作用,编译器会优化它吗? 是否需要一定程度的优
4回复

使用速记IF的C ++编译器优化

我在考虑关于精简if / else时优化编译器的问题。 我有这个功能: 我想知道什么更有效? 要么 在前一种情况下,编译器(在我的情况下为GCC 4.6.2)是否知道如何优化if / else以保持eucl_distance()的返回值可重复使用,而不是对其进行两次