在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函数的一般使用原则。