30. Understand the ins and outs of lining

透彻了解inling的里里外外

inline函数,看起来像函数,动作像函数,比宏好用得多,可以调用它们又不需要受函数调用所招致的额外开销。
inline函数背后的整体观念是,将“对此函数的每一个调用"都以函数本体替代之。但是这样可能会增加你的目标码(object code)。过度热衷inlining会造成程序体积太大

inline只是对编译器的一个申请,不是强制命令。这项申请可以隐喻提出,也可以明确提出

  • 隐喻方式将函数定义于class定义式内:
class Person
{
public:
	...
	int age() const { return theAge; } // 一个隐喻的inline申请
	...
private:
	int theAge;
}
  • 明确申明inline函数的做法则是在其定义式前加上关键字inline。
template<typename T>
inline const T& std::max(const T& a, const T& b)
{
	return a < b ? b : a;
}

大部分编译器拒绝将太过复杂的(带有循环或递归)函数inlining,而所有对virtual函数的调用也都会是linining落空。因为virtual因为"等待,知道运行期才确定调用哪个函数",而inline意味"执行前,先将调用动作替换成为被调用函数的本体。"

一个表面上看似inline的函数是否真的inline取决于运行环境,主要取决于编译器,幸运的是大多数表一起提供了一个诊断级别:
如果它们无法将你要求的函数inline化,会给出一个警告。

有时候虽然编译器有意愿inlining某个函数,还是可能为该函数生成一个函数本体。例如:
如果程序要去取某个inline函数的地址,编译器通常必须为此函数生成一个outlined函数本体。毕竟编译器没有能力提出一个指针指向并不存在的函数。

inline函数无法随着程序库的升级而升级。如果f是程序库内的一个inline函数,客户将"f函数本体"编进其程序中,一旦程序库设计这决定改变f,所有用到f的客户端程序都必须重新编译。如果f是non-inline函数,一旦又任何修改,客户端只需要重新连接就好,远比重新编译的负担少。如果程序采用动态连接,升级版函数甚至可以不知不觉地被应用程序吸纳。

大部分调试器面对inline函数都束手无策。因为没办法在一个并不存在的函数内设立断点。虽然某些环境中勉强支持对inline函数的调试,其他许多环境仅仅只能"在调试版程序中禁用发生inlining"。

请记住:

  • 将大多数inlining限制在小型、被频繁调用的函数身上。这可使日后的调试过程和二进制升级更容易,也可使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。
  • 不要只以为funciton template出现在头文件,就将它们声明为inline。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值