zoukankan      html  css  js  c++  java
  • inline-内联函数的优点以及与宏定义的区别

    inline函数的优点:

      C++ 语言的函数内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员。所以在C++ 程序中,应该用内联函数取代所有宏代码.

    inline函数与宏定义的区别:

    1.宏定义只是简单的文本替换,不做任何安全性的检查也不像函数那样在栈上创建新的变量空间.

      (1)宏定义可能会造成cxy不希望的变量多次累加;在下面F宏定义中基本上是x出现了几次就会被累加了几次.

    #define F(x) x+x
    #define F3(x) x+x+x
        int i = 0;
        cout<<F(i++)<<endl;//1  <=> (i++ + i ++) i is added twice
        cout<<i<<endl;//2
        int j = 0;
        cout<<F3(j++)<<endl;    //3
        cout<<j<<endl; //3

      (2)没有类型检查,可能传进来任意类型.

    #define MAX(a,b) ((a)>(b)?(a):(b))
    MAX(a,"Hello"); //错误地比较int和字符串,没有参数类型检查

    2.宏定义无法操作类的私有成员,而inline函数可以.

      综上,C++ 语言的函数内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员。所以在C++ 程序中,应该用内联函数取代所有宏代码.

      BUT , “断言assert”恐怕是唯一的例外。assert是仅在Debug版本起作用的宏,它用于检查“不应该”发生 的情况。为了不在程序的Debug版本和Release版本引起差别,assert不应该产生任何副作用。如果assert是函数,由于函数调用会引起内 存、代码的变动,那么将导致Debug版本与Release版本存在差异。所以assert不是函数,而是宏。

    inline函数用法:

    1.inline用于实现的关键字并不是生成类型关键字.比如如下定义并不起作用:  

    inline void foo();// inline仅与函数声明放在一起 
    void foo()
    {
    }

    而如下风格的函数Foo则成为内联函数: 

    void Foo(int x, int y);  
    inline void Foo(int x, int y) // inline与函数定义体放在一起 
    { 
    … 
    } 

    2.定义在类声明之中的成员函数将自动地成为内联函数(类声明与实现分离与否的重要区别),例如 

    class A 
    { 
    public: 
    void Foo(int x, int y) { … }  // 自动地成为内联函数 
    } 

    inline慎用:

      内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率 的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联: 
    (1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。 
    (2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。 
    类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。 
      一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了inline不应该出现在函数的声明中)。

    例题一道:

    关于c++的inline关键字,以下说法正确的是()
    正确答案: D 
    
    使用inline关键字的函数会被编译器在调用处展开 (不移地ing)
    头文件中可以包含inline函数的声明
    可以在同一个项目的不同源文件内定义函数名相同但实现不同的inline函数
    定义在Class声明内的成员函数默认是inline函数
    优先使用Class声明内定义的inline函数
    优先使用Class实现的内inline函数的实现

      内联不是你想展想展就能展!

    ANs:D

    A 如果只声明含有inline关键字,就没有内联的效果。 内联函数的定义必须放在头文件中, 编译器才能在调用点内联展开定义.   有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数.
    B 内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline 函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够的。
    C 当然内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它,而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。
    对于由两个文件compute.C和draw.C构成的程序来说,程序员不能定义这样的min()函数,它在compute.C中指一件事情,而在draw.C中指另外一件事情。如果两个定义不相同,程序将会有未定义的行为:

          为保证不会发生这样的事情,建议把inline函数的定义放到头文件中。在每个调用该inline函数的文件中包含该头文件。这种方法保证对每个inline函数只有一个定义,且程序员无需复制代码,并且不可能在程序的生命期中引起无意的不匹配的事情。

    D 正确。 定义在类声明之中的成员函数将自动地成为内联函数,例如:
    1
    class A {   public:  void Foo(int x, int y) { ... }   // 自动地成为内联函数   } 
     
    EF 在每个调用该inline函数的文件中包含该头文件。这种方法保证对每个inline函数只有一个定义,且程序员无需复制代码,并且不可能在程序的生命期中引起无意的不匹配的事情。最好只有一个定义!
  • 相关阅读:
    Android自动化测试中如何处理各种弹窗
    产品经理的私房菜
    Java基础——ArrayList方法全解(字典版)
    ESP8266 WIFI杀手汉化教程 &烧录
    c语言数据拼包
    阿里开源Java诊断工具--Arthas入门
    Java并发包9--Future接口简介
    官宣|VS Code 1.59 发布!Terminal 可以跨窗口移动了!
    微软内推常见问题 Q&A
    03-Numpy库
  • 原文地址:https://www.cnblogs.com/luntai/p/6251727.html
Copyright © 2011-2022 走看看