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

来源:互联网 发布:步兵番号 知乎 编辑:程序博客网 时间:2024/04/30 21:45

条款30:透彻了解inlining的里里外外
    (Understand the ins and outs of inlining.)

内容:
    对于该款的描述,原文中用了6页的篇幅进行阐述,这里我就将重要的知识点罗列出来,方便大家更好的理解
这一条款.
    (1)inline函数的优缺点.
    优点:对于一个inline函数,你可以调用它们又不蒙受函数调用招致的额外开销,编译器就会对函数本体执行
语境相关最优化,而大部分编译器不会对着一个非inline函数调用动作执行如此之最优化.
    缺点:由于对inline函数的每一个调用都以函数本体替换之,所以说这样就可能增加你的目标代码,在一台有
限的机器上,过度热衷inlining会造成程序体积太大,即使拥有虚拟内存,inline造成的代码膨胀亦会导致额外的
换页行为,降低指令高速缓存装置的击中率,以及伴随而来的效率损失.
    (2)inline只是对编译器的一个申请不是强制命令,该申请可以隐喻提出也可明确提出,隐喻提出就是将函数
定义于class定义式内,这样的函数通常是成员函数或者是friend函数.明确声明就是在函数之前加关键字"inline".
    (3)inline函数通常一定要被置于头文件内,其在大多数C++程序中是编译器行为.
    (4)大部分编译器拒绝将太过复杂的函数inlining,而所有的virtual函数都不能inlining,因为virtual意味
着"等待,知道运行期才确定调用哪个函数",而inline意味"执行前先将动作替换为被调用函数的本体".
如果编译器不知道该调用哪个函数,你就很难责备它们拒绝将函数本体inlining.
    (5)有时候编译器inline某个函数的同时,还可能为其生成一个函数本体(比如程序要取某个line函数地址),
值得一提的是,编译器通常不对"通过函数指针而进行的调用"实施inling,这就是说line函数的调用可能是
被inlined,也可能不被inlined,取决于调用的实施方式.
    (6)"将构造函数和析构函数进行inling"是一个很糟糕的想法.看下面这段代码:
    class Base{
    public:
        ...
    private:
        std::string bm1,bm2;
    };
    class Derived:public Base{
    public:
        Derived(){} //空函数耶,够简单了吧?我想让它inlining,可以么?
        ...
    private:
        std::string dm1,dm2,dm3;
    };
    这个构造函数看起来很简单,inlining它应该没问题嘛,呵呵,但你的眼睛可能会欺骗你.我们来看它的等价
代码:
    Derived::Derived(){ //"空白Derived构造函数"的观念性实现
        Base::Base();//初始化"Base成分"
       
        try{
            dm1.std::string::string();
        }catch(...){
            Base::~Base();
            throw;
        }
       
        try{
            dm2.std::string::string();
        }catch(...){
            dm1.std::string::~string();
            Base::~Base();
            throw;
        }
       
        try{
            dm3.std::string::string();
        }catch(...){
            dm2.std::string::~string();
            dm1.std::string::~string();
            Base::~Base();
            throw;
        }
    }
    这段代码并不能代表编译器真正制造出来的代码,因为真正的编译器会以更精致复杂的做法来处理异常.
尽管如此,这已能准确反映Derived的空白构造函数必须提供的行为.
    (7)程序库设计者必须评估"将函数声明为inline"的冲击:inline函数无法随着程序库的升级而升级.
    我认为的该款的重点都罗列出来了,如果有什么不明白的地方,请留言.
    请记住:
    ■ 将大多数inlining限制在小型,被频繁调用的函数身上.这可使日后的调试过程和二进制升级更容易,
也可使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化.
    ■ 不要因为function templates出现在头文件,就将它们声明为inline.