为什么在 C++ 中没有强制内联的标准方法?
C++ 旨在为程序员提供选择,即使这可能会让程序员做出错误的选择。
如果是这样设计的,为什么没有标准方法来强制编译器内联某些内容,即使我可能是错的?
或者我可以问为什么 inline
关键字只是一个提示?
我想我在这里别无选择。
在 OOP 世界中,我们调用对象的方法,并且应该避免直接访问成员。如果我们不能强制内联访问器,那么我们就无法编写高性能但仍可维护的应用程序。
(我知道许多编译器实现了自己的强制内联方法,但这很丑陋。使用宏在类上创建内联访问器也很丑陋。)
编译器总是比程序员做得更好吗?
According to the wikipedia C++ article
C++ is designed to give the programmer choice, even if this makes it possible for the programmer to choose incorrectly.
If it is designed this way why there is no standard way to force the compiler to inline something even if I might be wrong?
Or I can ask why is inline
keyword is just a hint?
I think I have no choice here.
In the OOP world we call methods on the objects and directly accessing members should be avoided. If we can't force the accessors to be inlined, then we are unable to write high performance but still maintainable applications.
(I know many compilers implement their own way to force inlining but it's ugly. Using macros to make inline accessors on a class are ugly too.)
Does the compiler always do it better than the programmer?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
编译器如何内联递归函数(特别是如果编译器不支持尾部调用优化,即使支持,该函数也不能进行尾部调用优化)。
这只是编译器应决定内联是否实用的原因之一。可能还有其他我现在想不起来的。
How would a compiler inline a recursive function (especially if the compiler does not support Tail-call optimization and even if it does, the function is not Tail-call optimize-able).
This is just one reason where compiler should decide whether inline is practical or not. There can be others as well which I cant think of right now.
不,并不总是……但是程序员更容易出错,并且不太可能在几年内保持最佳调整。最重要的是,如果函数非常小(对于至少一个公共/重要的代码路径),内联只会对性能有所帮助,但它可以帮助提高大约一个数量级,当然这取决于很多事情。对于程序员来说,评估通常是不切实际的,更不用说仔细关注函数的重要性,而且阈值可能会因编译器实现选择、命令行选项、CPU 模型等而异。函数 - 任何非内置类型都可以触发各种不同的行为(尤其是在模板中),可以重载运算符(甚至 new )的使用,调用约定和异常处理步骤的冗长性对于程序员来说通常并不明显。
很可能的是,如果编译器没有内联一些足够小的东西,让您可以期望内联后会得到有用的性能改进,那么编译器会意识到一些您没有意识到的实现问题,这实际上会使情况变得更糟。在那些灰色的情况下,编译器可能会采用任何一种方式,并且您刚刚超过某个阈值,无论如何,性能差异都不太可能很大。
此外,一些程序员(包括我自己)可能会偷懒,故意滥用
内联
作为将实现放入头文件中的便捷方法,从而绕过 ODR,即使他们知道这些函数很大,如果编译器(被要求)实际内联它们,那将是灾难性的。但这并不排除强制内联关键字/符号...它只是解释了为什么很难改变当前inline
关键字的期望。No, not always... but the programmer is far more error prone, and less likely to maintain the optimal tuning over a span of years. The bottom line is that inlining only helps performance if the function is really small (for at least one common/important code path) but then it can help by about an order of magnitude, depending on many things of course. It's often impractical for the programmer to assess let alone keep a careful eye on how trivial a function is, and the thresholds can vary with compiler implementation choices, command line options, CPU model etc.. There are so many things that could suddenly bloat a function - any non-builtin type can trigger all sorts of different behaviours (esp in templates), use of an operator (even
new
) can be overloaded, the verbosity of calling conventions and exception-handling steps aren't generally obvious to the programmer.The chances are that if the compiler isn't inlining something that's small enough for you to expect a useful performance improvement if it was inlined, then the compiler's aware of some implementation issue you're not that would actually make it worse. In those gray cases where the compiler might go either way and you're just over some threshold the performance difference isn't likely to be significant anyway.
Further, some programmers (myself included) can be lazy and deliberately abuse
inline
as a convenient way to put implementation in a header file, getting around the ODR, even though they know those functions are large and that it would be disastrous if the compiler (were required to) actually inline them. This doesn't preclude a forced-inline keyword/notation though... it just explains why it's hard to change the expectations around the currentinline
keyword.因为你“可能”比编译器更了解。
大多数时候,对于未标记为内联(且正确声明/定义)的函数,编译器将根据其配置和实现自行评估该函数是否可以内联。
例如,如果代码不长和/或太复杂,大多数编译器将自动内联标头中完全定义的成员函数。这是因为由于该函数在标头中可用,为什么不尽可能多地内联它呢?
然而这种情况不会发生,例如,在 Visual Studio 的调试模式下:在调试中,调试信息仍然需要映射函数的二进制代码,因此它避免内联,但仍然会将内联函数标记为内联,因为用户需要它。如果您想要标记不需要调试时信息(例如简单的 getter)的函数,同时在调试时获得更好的性能,那么这非常有用。
在发布模式下(默认情况下),编译器将积极内联所有可能的内容,即使您激活了调试信息,也使得调试代码的某些部分变得更加困难。
因此,一般的想法是,如果您以有助于编译器内联的方式编码,它将尽可能内联。如果您以难以或不可能内联的方式编写代码,则可以避免。如果您将某些内容标记为内联,您只需告诉编译器,如果它发现内联很难但并非不可能,则应该内联它。
由于内联取决于调用者和被调用者的上下文,因此没有“规则”。
通常建议的是简单地忽略显式标记函数内联,但在两种情况下:
不,这就是为什么有时使用 inline 关键字会有所帮助。有时,程序员比编译器对必要的东西有更好的总体了解。例如,如果程序员希望其二进制文件尽可能最小,则根据代码的不同,内联可能是有害的。在需要速度性能的应用程序中,积极内联可以提供很大帮助。编译器如何知道需要什么?必须对其进行配置,并允许它以细粒度的方式了解真正想要内联的内容。
Because you "might" know better than the compiler.
Most of the time, for functions not marked inline (and correctly declared/defined), the compiler, depending on it's configuration and implementation, will itself evaluate if the function can be inlined or not.
For example, most compilers will automatically inline member functions that are fully defined in the header, if the code is'isn't long and/or too complex. That's because as the function is available in the header, why not inline it as much as we can?
However this don't happen, for example, in Debug mode for Visual Studio : in Debug the debug informations still need to map the binary code of the functions, so it avoid inlining, but will still inline functions marked inline, because the user required it. That's useful if you want to mark functions yuo don't need to have debug-time informations (like simple getters) while getting better performance at debug-time.
In Release mode (by default) the compiler will agresively inline everything it can, making harder to debug some part of the code even if you activate debugging informations.
So, the general idea is that if you code in a way that helps the compiler inlining, it will inline as much as it can. If you write your code in ways that is hard or impossible to inline, it will avoid. If you mark something inline, you just tell the compiler that if it find it hard but not impossible to inline, it should inline it.
As inlining depends on both contexts of the caller and the callee, there is no "rule".
What's often advised is to simply ignore explicitly mark function inline but in two cases :
No, that's why sometimes using the inline keyword can help. The programmer can have sometimes a better general view of what's necessary than the compiler. For example, if the programmer wants it's binary to be the smallest possible, depending on code, inlining can be harmful. In speed performance required application, inlining aggressively can help very much. How would the compiler know what's required? It have to be configured and be allowed to know in a fine-grain way what is really wanted to be inline.
错误的假设。
有一种方法。它的拼写是
#define
。对于许多早期的 C 项目来说,这已经足够好了。inline
完全不同 - 提示,更好的语义 - 除了宏之外还可以添加它。但是一旦你同时拥有了两者,就没有剩下第三个选项的空间了,第三个选项具有更好的语义,但不是可选的。Mistaken assumption.
There is a way. It's spelled
#define
. And for many early C projects, that was good enough.inline
was sufficiently different - hint, better semantics - that it could be added besides macros. But once you had both, there was little room left for a third option in between, one with the nicer semantics but non-optional.如果您确实需要强制内联函数(为什么?),您可以这样做:复制代码并粘贴它,或者使用宏。
If you really need to force the inline of a function (why?), you can do it: copy the code and paste it, or use a macro.