Effective C++条款30:透彻了解inlining的里里外外

inline函数,可以调用它又不需要承受调用函数调用索导致的额外开销。此外,编译器最优化机制通常被设计用来浓缩那些不含函数调用的代码,所有当你inline某个函数,或许编译器就因此有能力对它进行最优化。

当然有利于也有弊:inline函数背后的原理是:对此函数的每一个调用都以函数本体替换之,显而易见的是,这样做很有可能增加你的目标代码大小。在一台内存有限的机器上,过度使用inline会导致程序体积太大,inline造成的代码膨胀会导致额外的换页行为,降低缓存的命中率,从而造成效率损失.

当然,如果inline函数很小,编译器针对函数本体产出的代码可能比针对函数调用所产出的代码更小。如果真是这样,将函数内联确实可能导致比较小的目标代码和较高的指令缓存击中率.

记住:inline只是对编译器的一个申请,不是强制命令.
一般在类声明中定义的函数都是内联的,这样的函数通常是成员函数.
friend函数也可以被定义在类内,它们也是隐喻声明为inline的.

明确声明inline函数的做法是在定义是前加上关键字inline 比如标准的max template往往这样实现:

template<typename T>
inline const T & std::max(const T&a, const T & b)
{return a < b ? b: a;}

大部分编译器拒绝将太过复杂(带有循环或者递归)的函数内联,而所有的虚函数的调用都会使无法内联,因为虚函数要知道运行期才能确定调用哪个函数,而inline意味着执行前,先将调用动作替换为被调用函数的本体.

有时候虽然编译器有意愿内联某个函数,还是可能为该函数生成一个函数本体。
比如:

inline void f(){...}
void (*pf)() = f;
..
f();//这个调用将内联
pf();//这个不会

因为如果函数指针要取f的地址,编译器必须为此函数生成一个非内联函数本体,毕竟编译器哪有能力提出一个指针指向并不存在的函数呢?

即使你不使用函数指针,还是有这种情况会发生,比如编译器会生成构造函数和析构函数的非内联副本,如此一来它们就可以获得指针指向那些函数。

实际上构造函数和析构函数是内联的不好选择,考虑以下代码:

class Base
{
	public:
		...
	private:
		string bm1,bm2;
}class Derived:public Base
{
public:
	Derived(){}
	...
private:
	string dm1, dm2, dm3;
};

其中Derived()看起来是内联的好选择,因为它不含任何代码,但是你的眼睛会欺骗你.
编译器为上面那个看起来为空的Derived构造函数所产生的代码,相当于以下所列:

Derived::Derived()
{
	Base::Base();
	try{dm1.std::string::string();}
	catch(...)
	{
		Base::~Base();
		throw;
	}
	try{dm2.std::string::string();}
	catch(...)
	{
		dm1.std::string::~string();
		Base::~Base();
		throw;
	}
	...
}

这段代码并不能代表编译器真正制造出来的代码,因为真正的情况会比这个更复杂。这说明了,表面上看上去空白的代码,实际确做了很多事情。

相同的理由也适用于Base构造函数,如果它被内联了,所有本体代码都会插入派生类构造函数里面。如果string也被内联了,上面这个例子中Derived构造函数将获得五份"string构造函数代码"副本。

所以说构造函数和析构函数不适合内联。

此外:inlineh函数无法随着程序库的升级而升级,还有大部分调试器面对inline函数都束手无策。毕竟你如何在一个并不存在的函数内设立断点呢?

总结:

1.将大多数内联限制在小型、被频繁调用的函数身上。这可使日后的调试过程和二进制升级更容易,也可以使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。
2.不要因为函数模板出现在头文件,就将它们声明为内联

3. 如果函数内的代码比较长,使用内联将导致内存消耗代价较高
4. 构造函数和析构函数不适合内联,不要随便将构造函数和析构函数的定义体放在类声明中

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值