C++箴言:理解inline化的介入和排除

C++箴言:理解inline化的介入和排除,第1张

C++箴言:理解inline化的介入和排除,第2张

内嵌函数——多么好的主意!它们看起来像函数,它们产生的效果也像函数。它们在各方面都比宏好得多,但是您可以调用它们而不会产生函数调用的开销。你还想要什么?

实际上,您得到的可能比您想象的要多,因为避免函数调用的成本只是故事的一部分。通常,编译器优化是为没有函数调用的连续代码段而设计的,因此当您内联一个函数时,您可以让编译器对函数体执行上下文相关的特殊优化。大多数编译器不会像这样优化“概述”函数调用。

但是,在编程中,就像生活中一样,没有免费的午餐,内联函数也不例外。内联函数背后的思想是用一个函数本体代替对这个函数的每一次调用,你不必拿着统计表中的博士学位就能看出这可能会增加你的目标代码的大小。在内存有限的机器上,过于热衷于内联会使程序太大,超出可用的空空间。即使使用虚拟内存,内联导致的代码膨胀也会导致额外的分页,降低指令缓存的命中率,以及随之而来的性能损失。

另一方面,如果内联函数体很短,为函数体生成的代码可能比函数调用生成的代码要小。如果是这样的话,内联这个函数实际上可以导致更小的目标代码和更高的指令缓存命中率!记住,内联是对编译器的请求,而不是命令。这种请求可以是显式的,也可以是隐式的。隐式方法是在类定义中定义一个函数:

class Person {
public:
...
int age()const { return the age;} //隐式内联请求:年龄为
...//在类定义中定义

private:
int the age;
};

这样的函数通常是成员函数,但是我们知道友元函数也可以在类内部定义。如果它们在那里,它们也被隐式声明为inline。

通过在声明前添加inline关键字来显式声明内联函数。例如,下面是标准max模板的常用实现方法(来自):

template//a explicit inline
inline const T & STD::max(const T & a,const T & b)//request:STD::max is
{ return a < b?乙:甲;} //以“inline”开头

max是一个模板的事实导致了一个观察结论:内联函数和模板一般都是在头文件中定义的。这导致一些程序员断定函数模板必须是内联的。这个结论是非法的,有潜在的危害,值得我们去调查。内联函数通常必须在头文件中,因为大多数构建环境在编译期间都是内联的。为了用被调用函数的函数本体替换函数调用,编译器必须知道函数是什么样子的。(有些构建环境可以在连接过程中内联,还有一些——例如,基于。NET公共语言基础结构(CLI)-可以在运行时内联。然而,这些环境是例外,而不是规则。在大多数C++程序中,内联是一种编译时行为。)

模板通常在头文件中,因为编译器需要知道模板的样子,以便在使用时实例化它。(同样,也不是全部。一些构建环境可以在连接期间实例化模板。然而,编译时实例化更常见。)模板实例化与内联无关。如果你写了一个模板,你认为所有从这个模板实例化的函数都应该是内联的,那么就把这个模板声明为内联的,上面std::max的实现就是这么做的。但是如果你为一个没有理由被内联的函数编写一个模板,避免将这个模板声明为内联的(无论是显式的还是隐式的)。内联是有成本的,你不想在不可预见的情况下遇到他们。我们已经讨论了内联是如何导致代码膨胀的,但是还有其他成本,我们将在后面讨论。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C++箴言:理解inline化的介入和排除

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情