C++ 中的常量和编译器优化
我已经阅读了 C++ 中关于 const 正确性的所有建议,并且它很重要(部分),因为它可以帮助编译器优化代码。 我从未见过关于编译器如何使用这些信息来优化代码的很好的解释,即使是好书也没有继续解释幕后发生的事情。
例如,编译器如何优化声明为 const 的方法与不是但应该声明为 const 的方法。 当引入可变变量时会发生什么? 它们会影响 const 方法的这些优化吗?
I've read all the advice on const-correctness in C++ and that it is important (in part) because it helps the compiler to optimize your code. What I've never seen is a good explanation on how the compiler uses this information to optimize the code, not even the good books go on explaining what happens behind the curtains.
For example, how does the compiler optimize a method that is declared const vs one that isn't but should be. What happens when you introduce mutable variables? Do they affect these optimizations of const methods?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
const 是直接优化的最明显的一点是向函数传递参数。 确保函数不会修改数据通常很重要,因此函数签名的唯一真正选择是:
当然,这里真正的魔力是传递引用而不是创建对象的(昂贵的)副本。 但如果引用没有标记为 const,这会削弱该函数的语义并产生负面影响(例如使错误跟踪变得更加困难)。 因此,
const
在这里启用了优化。/编辑:实际上,一个好的编译器可以分析函数的控制流,确定它不会修改参数并本身进行优化(传递引用而不是副本)。 这里的
const
只是对编译器的帮助。 然而,由于 C++ 有一些相当复杂的语义,并且这种控制流分析对于大型函数来说可能非常昂贵,因此我们可能不应该依赖编译器来实现这一点。 有人有任何数据支持我/证明我错了吗?/EDIT2:是的,一旦自定义复制构造函数发挥作用,它就会变得更加棘手,因为不幸的是,不允许编译器在这种情况下省略调用它们。
The most obvious point where
const
is a direct optimization is in passing arguments to a function. It's often important to ensure that the function doesn't modify the data so the only real choices for the function signature are these:Of course, the real magic here is passing a reference rather than creating an (expensive) copy of the object. But if the reference weren't marked as
const
, this would weaken the semantics of this function and have negative effects (such as making error-tracking harder). Therefore,const
enables an optimization here./EDIT: actually, a good compiler can analyze the control flow of the function, determine that it doesn't modify the argument and make the optimization (passing a reference rather than a copy) itself.
const
here is merely a help for the compiler. However, since C++ has some pretty complicated semantics and such control flow analysis can be very expensive for big functions, we probably shouldn't rely on compilers for this. Does anybody have any data to back me up / prove me wrong?/EDIT2: and yes, as soon as custom copy constructors come into play, it gets even trickier because compilers unfortunately aren't allowed to omit calling them in this situation.
此代码
输出:
这意味着 const 声明的对象已在 const 成员函数中更改。 C++ 语言中 const_cast(以及 mutable 关键字)的存在意味着 const 关键字无法帮助编译器生成优化的代码。 正如我在之前的文章中指出的,它甚至可以产生意想不到的结果。
作为基本规则:
事实上,这是一个合法的 C++ 修饰符:
This code,
outputs:
which means the const declared object has been altered in a const member function. The presence of const_cast (and the mutable keyword) in the C++ language means that the const keyword can't aide the compiler in generating optimised code. And as I pointed out in my previous posts, it can even produce unexpected results.
As a general rule:
In fact, this is a legal C++ modifier:
const
帮助编译器优化主要是因为它使您可以编写可优化的代码。 除非你输入const_cast
。const
helps compilers optimize mainly because it makes you write optimizable code. Unless you throw inconst_cast
.我认为const关键字主要是为了程序语义的编译检查而引入的,而不是为了优化。
Herb Sutter 在 GotW #81 文章 中很好地解释了为什么编译器不能通过 const 引用传递参数或声明 const 返回值时优化任何内容。 原因是编译器无法确保引用的对象不会更改,即使声明为 const :可以使用 const_cast,或者某些其他代码可以在同一对象上拥有非常量引用。
然而,引用 Herb Sutter 的文章:
本文还有很多内容,因此我鼓励您阅读它:之后您将对持续优化有更好的理解。
I think that the const keyword was primarily introduced for compilation checking of the program semantic, not for optimization.
Herb Sutter, in the GotW #81 article, explains very well why the compiler can't optimize anything when passing parameters by const reference, or when declaring const return value. The reason is that the compiler has no way to be sure that the object referenced won't be changed, even if declared const : one could use a const_cast, or some other code can have a non-const reference on the same object.
However, quoting Herb Sutter's article :
There is a lot more in this article, so I encourage you reading it: you'll have a better understanding of constant optimization after that.
让我们忽略方法,只看 const 对象; 编译器在这里有更多的优化机会。 如果一个对象被声明为 const,则 (ISO/IEC 14882:2003 7.1.5.1(4)):
让我们忽略可能具有可变成员的对象 - 编译器可以自由地假设该对象不会被修改,因此它可以产生显着的优化。 这些优化可以包括以下内容:
请注意,此内容仅适用于实际对象为 const 的情况 - 它不适用于通过 const 指针或引用访问的对象,因为这些访问路径可能会导致非 const 对象(甚至更好) - 定义为通过 const 指针/引用更改对象,只要实际对象是非常量,并且您放弃了对象访问路径的常量性)。
实际上,我认为没有编译器可以对所有类型的 const 对象执行任何重要的优化。 但对于原始类型(整数、字符等)的对象,我认为编译器在优化方面可能非常积极
这些物品的使用。
Let's disregard methods and look only at const objects; the compiler has much more opportunity for optimization here. If an object is declared const, then (ISO/IEC 14882:2003 7.1.5.1(4)):
Lets disregard objects that may have mutable members - the compiler is free to assume that the object will not be modified, therefore it can produce significant optimizations. These optimizations can include things like:
Note that this stuff applies only if the actual object is const - it does not apply to objects that are accessed through const pointers or references because those access paths can lead to objects that are not const (it's even well-defined to change objects though const pointers/references as long as the actual object is non-const and you cast away the constness of the access path to the object).
In practice, I don't think there are compilers out there that perform any significant optimizations for all kinds of const objects. but for objects that are primitive types (ints, chars, etc.) I think that compilers can be quite aggressive in optimizing
the use of those items.
handwaving 开始
从本质上讲,数据越早被修复,编译器就越能在数据的实际分配中移动,确保管道不会停止
end handwaving
handwaving begins
Essentially, the earlier the data is fixed, the more the compiler can move around the actual assignment of the data, ensuring that the pipeline doesn't stall out
end handwaving
嗯。 常量正确性更多的是一种样式/错误检查而不是优化。 全面优化的编译器将跟踪变量的使用情况,并可以检测变量何时是有效的 const。
除此之外,编译器不能依赖你告诉它真相——你可能会丢弃它不知道的库函数中的 const 。
所以,是的,常量正确性是一个值得追求的目标,但它不会告诉编译器任何它自己无法弄清楚的事情,假设有一个良好的优化编译器。
Meh. Const-correctness is more of a style / error-checking thing than an optimisation. A full-on optimising compiler will follow variable usage and can detect when a variable is effectively const or not.
Added to that, the compiler cannot rely on you telling it the truth - you could be casting away the const inside a library function it doesn't know about.
So yes, const-correctness is a worthy thing to aim for, but it doesn't tell the compiler anything it won't figure out for itself, assuming a good optimising compiler.
它不会优化声明为 const 的函数。
它可以优化调用声明为const的函数的函数。
这里要调用 Fling,值 A.m_val 必须加载到 CPU 寄存器中。 如果 someFunc() 不是 const,则必须在调用 Flong() 之前重新加载该值。 如果 someFunc 是 const,那么我们可以使用仍在寄存器中的值调用 Flong。
It does not optimize the function that is declared const.
It can optimize functions that call the function that is declared const.
Here to call Fling, the valud A.m_val had to be loaded into a CPU register. If someFunc() is not const, the value would have to be reloaded before calling Flong(). If someFunc is const, then we can call Flong with the value that's still in the register.
将方法设置为const的主要原因是为了const的正确性,而不是为了方法本身可能的编译优化。
如果变量是const,那么它们(理论上)可以被优化掉。 但编译器只能看到范围。 毕竟编译器必须允许在其他地方使用 const_cast 修改它们。
The main reason for having methods as const is for const correctness, not for possible compilation optimization of the method itself.
If variables are const they can (in theory) be optimized away. But only is the scope can be seen by the compiler. After all the compiler must allow for them to be modified with a const_cast elsewhere.
这些都是正确的答案,但答案和问题似乎假定了一件事:编译器优化实际上很重要。
只有一种代码对编译器优化很重要,即在
如果其他 99% 的代码被优化到 N 级,那不会有什么不同,因为它只在程序计数器实际花费时间的代码中重要(您可以通过抽样找到)。
Those are all true answers, but the answers and the question seem to presume one thing: that compiler optimization actually matters.
There is only one kind of code where compiler optimization matters, that is in code that is
If the other 99% of the code is optimized to the Nth degree, it won't make a hoot of difference, because it only matters in code where the program counter actually spends time (which you can find by sampling).
如果优化器实际上将大量库存放入 const 声明中,我会感到惊讶。 有很多代码最终会抛弃常量性,这将是一个非常鲁莽的优化器,它依赖于程序员声明来假设状态何时可能改变。
I would be surprised if the optimizer actually puts much stock into a const declaration. There is a lot of code that will end up casting const-ness away, it would be a very reckless optimizer that relied on the programmer declaration to assume when the state may change.
const-正确性作为文档也很有用。 如果函数或参数被列为 const,我不需要担心代码中的值发生变化(除非团队中的其他人非常顽皮)。 不过,如果它没有内置到库中,我不确定它是否真的值得。
const-correctness is also useful as documentation. If a function or parameter is listed as const, I don't need to worry about the value changing out from under my code (unless somebody else on the team is being very naughty). I'm not sure it would be actually worth it if it wasn't built into the library, though.