Par*_*ial 526 c++ inline one-definition-rule
我应该何时inline
在C++中为函数/方法编写关键字?
看到一些答案,一些相关的问题:
我应该何时不写在C++函数/方法关键字"内联"?
什么时候编译器不知道何时使函数/方法'内联'?
当一个应用程序为函数/方法写入"内联"时,是否多线程是否重要?
def*_*ode 822
哦,男人,我的一个宠儿小便.
inline
更像是static
或extern
不是指令告诉编译器内联你的函数. extern
,static
,inline
是联动指令,几乎完全是由连接器,而不是编译器使用.
据说,inline
您认为函数应该内联到编译器的提示.这可能是在1998年,但十年后编译器不需要这样的提示.更不用说人类在优化代码时通常是错误的,因此大多数编译器都会忽略"提示".
static
- 变量/函数名称不能用于其他翻译单元.链接器需要确保它不会意外地使用来自另一个翻译单元的静态定义的变量/函数.
extern
- 在此翻译单元中使用此变量/函数名称,但如果未定义,则不会抱怨.链接器将对其进行排序,并确保尝试使用某些extern符号的所有代码都具有其地址.
inline
- 此功能将在多个翻译单元中定义,不用担心.链接器需要确保所有转换单元都使用变量/函数的单个实例.
注意:通常,声明模板inline
是没有意义的,因为它们已经具有链接语义inline
.但是,需要使用inline
模板的专门化和实例化.private
您问题的具体答案:
我应该何时在C++中为函数/方法编写关键字'inline'?
仅当您希望在标题中定义函数时.更确切地说,只有当函数的定义可以显示在多个翻译单元中时.最好在头文件中定义小(如在一个线性中)函数,因为它为编译器提供了更多信息,以便在优化代码时使用.它还会增加编译时间.
什么时候不应该为C++中的函数/方法编写关键字'inline'?
不要仅仅因为您认为如果编译器内联它会使代码运行得更快而添加内联.
什么时候编译器不知道何时使函数/方法'内联'?
通常,编译器将能够比您更好地完成此操作.但是,如果编译器没有函数定义,则编译器无法内联代码.在最大限度优化的代码__attribute__(( noinline ))
中,无论您是否要求,通常都会内联所有方法.
另外,为防止在GCC中内联,请使用__declspec(noinline)
,并在Visual Studio中使用inline
.
当一个应用程序为函数/方法写入"内联"时,是否多线程是否重要?
多线程不会以任何方式影响内联.
Ala*_*off 48
我想通过一个令人信服的例子来为这个主题中的所有重要答案做出贡献,以驱散任何剩余的误解.
给出两个源文件,例如:
inline111.cpp:
#include <iostream>
void bar();
inline int fun() {
return 111;
}
int main() {
std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun;
bar();
}
Run Code Online (Sandbox Code Playgroud)inline222.cpp:
#include <iostream>
inline int fun() {
return 222;
}
void bar() {
std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun;
}
Run Code Online (Sandbox Code Playgroud)案例A:
编译:
g++ -std=c++11 inline111.cpp inline222.cpp
Run Code Online (Sandbox Code Playgroud)
输出:
inline111: fun() = 111, &fun = 0x4029a0
inline222: fun() = 111, &fun = 0x4029a0
Run Code Online (Sandbox Code Playgroud)
讨论:
即使你应该对你的内联函数有相同的定义,如果不是这样的话,C++编译器也不会标记它(实际上,由于单独的编译它没有办法检查它).确保这一点是你自己的责任!
链接器不会抱怨一个定义规则,如fun()
声明的那样inline
.但是,因为inline111.cpp是fun()
由编译器处理的第一个转换单元(实际调用),所以编译器在inline111.cpp中首次调用遇到fun()
它时进行实例化.如果编译器决定不扩大从其他地方在你的程序在其呼叫(如从inline222.cpp),调用将被链接到从生产它的实例inline111.cpp(调用内部inline222.cpp也可能会产生一个该翻译单元中的实例,但它将保持不链接状态).实际上,从相同的打印输出中可以看出这一点.fun()
fun()
fun()
&fun = 0x4029a0
最后,尽管inline
建议,编译器实际上扩大了一行程序fun()
,它忽略了彻底你的建议,这是明显的,因为fun() = 111
在这两个线.
案例B:
编译 (注意逆序):
g++ -std=c++11 inline222.cpp inline111.cpp
Run Code Online (Sandbox Code Playgroud)
输出:
inline111: fun() = 222, &fun = 0x402980
inline222: fun() = 222, &fun = 0x402980
Run Code Online (Sandbox Code Playgroud)
讨论:
本案例断言案例A中讨论过的内容.
请注意一个重要的观点,如果你注释掉实际调用fun()
在inline222.cpp(如注释掉cout
的语句来inline222.cpp完全),那么,尽管你的翻译单元的编译顺序,fun()
将在它被实例化的第一个电话中相遇inline111.cpp,从而使打印出的情况B作为inline111: fun() = 111, &fun = 0x402980
.
案例C:
编译 (注意-O2):
g++ -std=c++11 -O2 inline222.cpp inline111.cpp
Run Code Online (Sandbox Code Playgroud)
要么
g++ -std=c++11 -O2 inline111.cpp inline222.cpp
Run Code Online (Sandbox Code Playgroud)
输出:
inline111: fun() = 111, &fun = 0x402900
inline222: fun() = 222, &fun = 0x402900
Run Code Online (Sandbox Code Playgroud)
讨论:
-O2
优化编译鼓励以实实在在地扩大可内联函数(另请注意,-fno-inline
是默认不优化选项).如从此处的outprint明显看出,fun()
实际上已经被扩展内联(根据其在该定义特定翻译单元),得到两个不同的 fun()
打印输出.尽管如此,仍然只有一个全球链接的实例fun()
(根据标准的要求),从相同的 &fun
打印输出中可以看出.Ari*_*yck 20
1)如今,几乎从来没有.如果内联函数是个好主意,编译器将在没有您帮助的情况下完成.
2)总是.见#1.
(编辑反映你把问题分成两个问题......)
Joh*_*itb 12
什么时候不应该为C++中的函数/方法编写关键字'inline'?
如果该函数的定义.cpp
文件,你应该不写关键字.
什么时候编译器不知道何时使函数/方法'内联'?
没有这种情况.编译器无法使内联函数.它所能做的就是内联部分或全部函数调用.如果它没有得到函数的代码就不能这样做(在这种情况下,链接器需要这样做才能这样做).
当一个应用程序为函数/方法写入"内联"时,是否多线程是否重要?
不,这根本不重要.
小智 5
这取决于使用的编译器.不要盲目相信现在的编译器比人类更了解如何内联,你不应该出于性能原因使用它,因为它是连接指令而不是优化提示.虽然我同意在意识形态上这些论点正确地遇到现实可能是另一回事.
在阅读了多个线程后,我尝试了好奇内联对我正在工作的代码的影响,结果是我为GCC获得了可测量的加速并且没有为英特尔编译器加速.
(更多细节:在类外定义的几个关键函数的数学模拟,GCC 4.6.3(g ++ -O3),ICC 13.1.0(icpc -O3);向关键点添加内联导致GCC代码加速+ 6%).
因此,如果您将GCC 4.6限定为现代编译器,结果是如果您编写CPU密集型任务并知道确切的瓶颈位置,则内联指令仍然很重要.
归档时间: |
|
查看次数: |
115670 次 |
最近记录: |