我在Scott Meyers的Effective c++书中读到:
当你内联一个函数时,你可以让编译器在函数体上执行特定于上下文的优化。这样的优化对于普通的函数调用是不可能的。
现在的问题是:什么是特定于上下文的优化,为什么它是必要的?
我不认为"特定于上下文的优化"是一个定义的术语,但我认为它基本上意味着编译器可以分析调用地点和周围的代码,并使用这些信息来优化函数。
这里有一个例子。当然,它是人为的,但它应该展示了这个想法:
功能:
int foo(int i)
{
if (i < 0) throw std::invalid_argument("");
return -i;
}
调用网站:
int bar()
{
int i = 5;
return foo(i);
}
如果单独编译foo
,它必须包含比较和异常抛出代码。如果它内联在bar
中,编译器会看到以下代码:
int bar()
{
int i = 5;
if (i < 0) throw std::invalid_argument("");
return -i;
}
任何合理的优化器都会将其计算为
int bar()
{
return -5;
}
如果编译器选择内联函数,它将用函数体替换对该函数的函数调用。现在在调用函数体中有更多代码需要优化。因此,它通常会产生更好的代码。
想象一下:
bool callee(bool a){
if(a) return false;
else return true;
}
void caller(){
if(callee(true)){
//Do something
}
//Do something
}
一旦内联,代码将像这样(近似地):
void caller(){
bool a = true;
bool ret;
if(a) ret = false;
else ret = true;
if(ret){
//Do something
}
//Do something
}
还可以进一步优化:
void caller(){
if(false){
//Do something
}
//Do something
}
然后到:
void caller(){
//Do something
}
函数现在小得多了,你没有函数调用的成本,特别是(关于这个问题)分支的成本。
假设函数为
void fun( bool b) { if(b) do_sth1(); else do_sth2(); }
,它在带有预定义的false
参数
bool param = false;
...
fun( param);
则编译器可以将函数体缩减为
...
do_sth2();
我不认为上下文特定的优化意味着特定的东西,你可能找不到确切的定义。
很好的例子是一些类属性的经典getter,没有内联程序必须:
- 跳转到getter主体
- 移动值到注册表(
eax
在x86
在windows下与默认的Visual studio设置) - 跳转回被调用对象
- 将
eax
的值移动到本地变量
而使用内联可以跳过几乎所有的工作,直接将值移动到局部变量。
优化严格依赖于编译器,但可能会发生很多事情(变量分配可能会被跳过,代码可能会重新排序等等…但是你总是保存call/jump,这是一个昂贵的指令。