inline函数的使用和理解

        在C++中,inline函数是一种比较小巧的函数。将函数声明为inline,该函数就成为内联函数。内联函数使函数的调用成本大大降低,因为编译器通常会对内联函数进行优化,如果inline函数的本体很小,编译器对内联函数的优化会使编译后产生的目标码比不使用内联函数产生的目标码更小,编译器对内联函数一般都是对每一个调用到该内联函数的地方都以函数本体替换,所以也使其执行速率大大提高。但如果使用不得当,大量的本体替换也可能会使最终的目标码很大,这对一台内存有限的嵌入式机器来说,反而会有相反的结果,所以合理的理解并使用inline函数是很有必要的。

        1、inline函数经常可以用来替换一些形似函数的宏,如:

//以a和b较大的值调用func函数
#define CALLMAX(a, b) func((a) > (b) ? (a) : (b))

        按这个宏的操作方式,如果这样使用:

int a = 5, b = 0;
CALLMAX(++a, b);         //func(7)  -> a = 7, b = 0;
CALLMAX(++a, b + 10);    //func(10)  -> a = 6, b =10

        使用宏的方式,会使a被异常累加,会影响后面对变量a的使用。所以以宏去实现一个形似函数的功能不如使用inline函数替换:

template<typename T>
inline void callMax(const T& a, const T& b)
{
    func(a > b ? a : b);
}

        除了将这样的宏使用inline替换可以防止参数被更改,且inline函数也是函数,它有作用域一说,可以将其定义为class的private成分,一般来说,宏没有这种功能。

        2、inline的隐式和显式声明:

        inline函数有隐式和显式两种声明方式,隐式的声明方式如这样:

class Animal 
{
public:
    ...
    int number() const { return theNum; }    //隐式的inline
    ...
private:
    int theNum;
};

        显式声明就是直接在函数定义式前加inline声明,如上面第1条中的程序。

        3、inline函数通常都置于头文件内:

        因为inline函数通常都是编译器将函数本体替换到所调用的地方,所以一般都将inline函数声明到头文件内。但它与template无关,在很多代码中,经常见到使用template声明的接口总是使用inline声明,其实它们是无关联的,在需要inline的时候就是用inline,不需要inline的时候就不要使用inline。

        4、无法被inline的情况:

        如果函数比较复杂,比如内部有循环或递归的函数,或有对virtual函数的调用声明为inline,则编译器无法真正将它inline化。或者,当使用函数指针的方式去调用内联函数时,也是无法真正inline化的:

inline void func() {...}    //func为一个声明为inline的函数
void (*pfunc)() = f;        //pfunc指向f
...

func();                     //这种调用可以被inline
pfunc();                    //这种调用不能够被inline

        5、尽量不要对构造函数和析构函数inline:

        假如有这样的两个继承类:

class Base
{
public:
    ...
private:
    std::string bm1, bm2;
};

class Derived: public Base
{
public:
    Derived() {}       //inline,但实现是空的
    ...
private:
    std::string dm1, dm2;
};

        对继承类Derived的构造函数隐式inline,虽然看起来里面是一个空实现,但实际上,在编译器看来,内部其实被本体替换为(大致代码):

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;
    }
    
}

        这只是很小的类,如果类很大,内部的声明变量众多,且继承关系复杂,将构造函数inline化,会使代码更加膨胀,有可能会影响性能和速度。所以最好不要对构造和析构函数inline。

        6、不要过多的使用inine函数:

        inline函数的特点使得在过多使用inline函数时,会使代码的可移植性降低。如果func函数是inline函数,那么一旦哪一天改变了func函数的实现方式,那所有用到func函数的地方都需要重新编译。并且,对程序调试而言,大部分inline函数无法调试,所以如果使用过多,代码的可调试性也会降低。所以,一般都是在在小型且调用很频繁的函数身上,将其声明成inline函数,是程序的效率提升上去。这就是inline函数的一般使用原则。

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: C++中的函数宏定义和内联函数有一些区别。函数宏定义是在预编译阶段将宏名替换为宏体,它不是真正的函数,而是一种字符串替换的机制。宏定义没有类型检查,无论对还是错都会直接替换。而内联函数是真正的函数使用inline修饰,编译器会在调用内联函数的地方展开,没有函数压栈的开销,提高了程序的运行效率。内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,如while、switch,并且内联函数本身不能直接调用自身。如果内联函数函数体过大,编译器会自动将其变为普通函数。内联函数在编译阶段进行代码插入,而宏定义是在预编译阶段进行代码展开。因此,内联函数在编译时会进行类型检查,而宏定义没有类型检查。此外,内联函数使用可以提高程序的效率,而宏定义的使用可以省去函数调用的开销。\[1\]\[2\] 然而,需要注意的是,宏定义和内联函数使用时都是进行代码展开。对于宏定义,预处理器会将所有的宏名替换为宏体;而对于内联函数,编译器会在每处调用内联函数的地方直接将内联函数的内容展开。这样可以省去函数压栈退栈的开销,提高了程序的效率。\[2\] 举个例子来说明宏定义和内联函数的区别。假设有以下代码: #include <iostream> using namespace std; #define MAX(a,b) (a > b ? a:b) int main() { int a = 10; int b = 20; cout << MAX(a, ++b) << endl; return 0; } 这段代码中,宏定义MAX(a, b)会将a和b进行比较,并返回较大的值。在调用MAX(a, ++b)时,宏定义会将其展开为(a > ++b ? a:b)。由于宏定义是字符串替换,所以++b会被展开两次,导致b的值增加了两次。因此,输出结果为22。\[3\] #### 引用[.reference_title] - *1* *3* [C++:在代码中理解宏定义和内联函数](https://blog.csdn.net/qq_43825377/article/details/116211242)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [C++中内联函数和宏定义](https://blog.csdn.net/luolaihua2018/article/details/115377860)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值