转:容易被误解的inline

C++中的inline是个容易被误解的关键字,即使是专家也常会犯错。
不信?请打开《Thinking in C++ 2rd Edition Volumn  1》,找到Chapter 9  "Inline Function"的Exercise 6:
“Prove that inline functions default to internal linkage."
为什么我说这里作者犯错了呢?因为C++ 03标准中角标79处明确写到:
“  The inline keyword has no effect on the linkage of a function.“  
看,标准明确表示inline关键字不对函数的linkage产生影响,作者却要读者试图证明inline function默认为internal linkage!

关于inline,我觉得最好的参考还是水木CplusPlus版的FAQ
http://www.newsmth.net/bbscon.php?bid=335&id=146496
以下内容基本来自于该FAQ,并加入了自己的一些理解和解释
误解一:inline函数没有单独的函数体,也不能取地址。
事实:inline修饰并不会改变函数的通常语义,仍可通过函数指针调用:
误解二:inline和virtual不能同时修饰一个函数。
事实:inline和virtual并不冲突,可以同时修饰函数
误解三:virtual函数即使声明为inline,由于是late binding,无法判断实际调用的版本,编译器也无法展开。
事实:虚函数调用并不总是late binding;late binding发生在通过指针或引用来调用函数的时候,在其它情况下理论上是可能对 virtual inline的函数进行展开的
误解四: inline函数一定是internal linkage/no linkage的。
inline 与函数的linkage无关。inline函数同样可以用static和extern修饰,并具备同一般函数相同的linkage。标准要求 external linkage的inline函数在所有编译单元中具有相同的地址。external linkage的inline函数内定义的静态变量同样应在所有编译单元中表现为单一对象,具有相同的地址。

这一条估计是最让人困惑的特 性了。因为通常inline函数的定义都放在头文件中,习惯了C++头文件使用规定的人都自然的将inline函数视为internal linkage。“如果是external linkage的话,该头文件被多个源文件包含的话,就会出现多次定义的错误了啊!”

对于正常的函数,这是正确的——头文件中应该包含函数的声明而不是定义。但是inline function 在这个问题上被特别对待。
TC++PL 9.2中写道:"一个inline函数必须在需要使用它的每个编译单元(TU)里定义——通过完全一样的定义"
C++ 03 [7.1.2.4]中对应的文字:
"An inline function shall be defined in every translation unit in which it is used and shall have exactly the same definition in every case (3.2).If a function with external linkage is declared inline in one  translation unit, it shall be declared inline in all translation units in which it appears; no diagnostic is required.
An inline function with external linkage shall have the same address in all translation units.
A static local variable in an extern inline function always refers to the same object.
A string literal in anextern inline function is the same object in different translation units."

注意上面用红色引用的这两条要求,这两条翻译成大白话就是:“我保证external  linkage的inline function在最终的可运行程序中只有一份实体,所以你就放心的在头文件中包含inline function的定义吧!“

所以,要分清楚事情的因果关系:不能因为头文件中可以包含inline function的定义,就想当然的认定inline function默认情况下是internal linkage。真相是相反的,因为标准为external linkage的 inline function 提供了特殊待遇,才能在头文件中包含inline function的定义。
一定要注意:这两条特殊待遇只对external linkage的inline function有效,对internal linkage的inline function是无效的
C++03中的[3.2.3]和[3.2.5] 也提供了与inline function的一些约定

最后是一个简单的示例程序,可以很好的用于区分概念
// a.h
inline  int eif(){
    
static int n=0;
    
return ++n;
}

static inline  int iif(){
    
static int n=0;
    
return ++n;
}

static int nif() {
    
static int n=0;
    
return ++n;
}

int eig();
int iig();
int nig();


// a.cpp
#include "a.h"
int eig() return eif(); }
int iig() {return iif();}
int nig() {return nif();}


//main.cpp
#include "a.h"
#include 
<iostream>
using namespace std;
int main() {
    cout
<<"external inline function ";
    cout
<<eig()<<' ';
    cout
<<eif()<<' ';

    cout
<<"internal inline function ";
    cout
<<iig()<<' ';
    cout
<<iif()<<' ';
    
    cout
<<"non-inline function ";
    cout
<<nig()<<' ';
    cout
<<nif()<<' ';
    
return 0;
}
external inline function
1
2
internal inline function
1
1
non
-inline function
1
1
posted @ 2012-02-27 23:33  Mr.Rico  阅读(687)  评论(0编辑  收藏  举报