在C语言中,如果一些函数被频繁调用,不断地有函数入栈,即函数栈,会造成栈空间或栈内存的大量消耗。
为了解决这个问题,特别的引入了inline修饰符,表示为内联函数。
inline函数的优点:
inline函数的缺点:
记住,inline只是对编译器的一个申请,不是强制命名。这项申请可能隐喻提出,也可以明确提出。
class Person{
public:
int age() const {return theAge; } // 隐式inline
private:
int theAge;
};
template<typename T>
inline const T& std::max(const T&a, const T&b){
return a < b ? b : a;
}
1、关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用。
如下风格的函数Foo 不能成为内联函数:
inline void Foo(int x, int y); // inline 仅与函数声明放在一起 void Foo(int x, int y) { }
而如下风格的函数Foo 则成为内联函数:
void Foo(int x, int y); inline void Foo(int x, int y) // inline 与函数定义体放在一起 { }
尽管在大多数教科书中内联函数的声明、定义体前面都加了inline 关键字,但inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。
2、关于头文件
3、inline的使用是有所限制的。inline只是对编译器的一个申请,编译器可以加以忽略。
virtual
意味着”等待,直到运行期才确定调用哪个函数“,而inline
意味着"执行前,先将调用动作替换为被调用函数的本体"。如果编译器不知道该调用哪个函数就不会inlininginline void f() { }; // 假设编译器有意愿inlining"对f的调用"
voiud (*pf)();
f(); // 这个调用将被inlined,因为它是一个正常调用
pf(); // 版本inlined,因为它通过函数指针达成
class Base{
...
private:
std::string bm1, bm2;
};
class Derived : public Base{
public:
Derived(){} //它真的为空吗?
...
private:
std::string dm1, dm2, dm3;
};
C++对于”对象被创建和被销毁时发生什么事“做了各式各样的保证:
也就是说Derived构造函数不一定为空:
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;
}
// ...
}
析构函数也是如此。
内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?
以下情况不宜使用内联:
(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。只有当函数只有 10 行甚至更少时才将其定义为内联函数.
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了inline 不应该出现在函数的声明中)。
因此, 慎用内联。当你决定哪些函数应该被声明为inline时,策略如下:一开始先不要将任何函数声明为inline,或者事少将inlining施行范围内的那些”一定成为内联“或者”十分平淡无奇“(比如Person::agr)的函数身上
因此,将内联函数放在头文件里实现是合适的,省却你为每个文件实现一次的麻烦.而所以声明跟定义要一致,其实是指,如果在每个文件里都实现一次该内联函数的话,那么,最好保证每个定义都是一样的,否则,将会引起未定义的行为,即是说,如果不是每个文件里的定义都一样,那么,编译器展开的是哪一个,那要看具体的编译器而定.所以,最好将内联函数定义放在头文件中.