理解inline化的介入和排除 (2)

2008-02-23 05:28:36来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

max 是个模板的事实引出一个观察结论:inline 函数和模板一般都是定义在头文档中的。这就使得一些程式员得出结论断定函数模板必须是 inline。这个结论是非法的而且有潜在的危害,所以他值得我们考察一下。 inline 函数一般必须在头文档内,因为大多数构建环境在编译期间进行 inline 化。为了用被调用函数的函数本体替换一个函数调用,编译器必须知道函数看起来像什么样子。(有一些构建环境能够在连接期间进行 inline 化,更有少数几个——比如,基于 .NET Common Language Infrastructure (CLI) 的控制环境——居然能在运行时 inline 化。然而,这些环境都是例外,并非规则。inline 化在大多数 C 程式中是个编译时行为。)

  模板一般在头文档内,因为编译器需要知道一个模板看起来像什么以便用到他时对他进行实例化。(同样,也不是全部如此。一些构建环境能够在连接期间进行模板实例化。然而,编译期实例化更为普遍。) 模板实例化和 inline 化无关。假如您写了一个模板,而且您认为任何从这个模板实例化出来的函数都应该是 inline 的,那么就声明这个模板为 inline,这就是上面的 std::max 的实现被做的事情。但是假如您为没有理由要 inline 化的函数写了一个模板,就要避免声明这个模板为 inline(无论显式的还是隐式的)。inline 化是有成本的,而且您不希望在毫无预见的情况下遭遇他们。我们已说到 inline 化是如何引起代码膨胀的,但是,更有其他的成本,过一会儿我们再讨论。

  在做这件事之前,我们先来完成对这个结论的考察:inline 是个编译器可能忽略的请求。大多数编译器拒绝他们认为太复杂的 inline 函数(例如,那些包含循环或递归的),而且,除了最细碎的以外的全部虚拟函数的调用都不会被 inline 化。不应该对这后一个结论感到惊讶。虚拟意味着“等待,直到运行时才能断定哪一个函数被调用”,而 inline 意味着“执行之前,用被调用函数取代调用的地方”。假如编译器不知道哪一个函数将被调用,您很难责备他们拒绝 inline 化这个函数本体。

  任何这些加在一起,得出:一个被指定的 inline 函数是否能真的被 inline 化,取决于您所使用的构建环境——主要是编译器。幸运的是,大多数编译器都有一个诊断层次,在他们不能 inline 化一个您提出的函数时,会导致一个警告。

  有时候,即使当编译器完全心甘情愿地 inline 化一个函数,他们还是会为这个 inline 函数生成函数本体。例如,假如您的程式要持有一个 inline 函数的地址,编译器必须为他生成一个 outlined 函数本体。他们怎么能生成一个指向根本不存在的函数的指针呢?再加上,编译器一般不会对通过函数指针的调用进行 inline 化,这就意味着,对一个 inline 函数的调用可能被也可能不被 inline 化,依赖于这个调用是如何做成的:

inline void f() {...} // assume compilers are willing to inline calls to f

void (*pf)() = f; // pf points to f
...

f(); // this call will be inlined, because it’s a "normal" call
pf(); // this call probably won’t be, because it’s through
// a function pointer




标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: 理解inline化的介入和排除 (3)

下一篇: 理解inline化的介入和排除 (1)

热门词条
热门标签