【发布时间】:2023-03-10 02:55:01
【问题描述】:
如果我们在类定义本身中定义一个成员函数,它是否必须被内联处理,或者它只是对编译器的一个可以忽略的请求。
【问题讨论】:
标签: c++ inline-functions
如果我们在类定义本身中定义一个成员函数,它是否必须被内联处理,或者它只是对编译器的一个可以忽略的请求。
【问题讨论】:
标签: c++ inline-functions
是的,在类体内定义的函数隐式为inline。
(与声明为inline 的其他函数一样,这并不意味着编译器必须在调用函数的地方执行内联扩展,它只是启用“单一定义规则”的允许放宽,并结合要求定义必须包含在使用该函数的所有翻译单元中。)
【讨论】:
正如其他人所说,在类中定义的方法会自动内联请求。 了解原因很有用。
假设不是。您必须为这样的函数生成代码,并且无论在何处调用它,跳转到子程序的指令都必须通过链接器引用该位置。
class A {
public:
void f() { ... your code ... }
};
每次看到这段代码,如果它不是内联的,编译器只能假设它必须被生成,所以它会生成一个符号。假设它是这样的:
A__f_v:
如果那个符号是全局的,那么如果你碰巧在不同的模块中多次包含这个类代码,你会在链接时遇到多重定义的符号错误。所以它不可能是全球性的。相反,它是本地文件。
假设您将上述头文件包含在多个模块中。在每一个中,它将生成该代码的本地副本。这比根本不编译要好,但是当你真的只需要一个时,你会得到多个代码副本。
这导致以下结论:如果您的编译器不打算内联函数,那么最好在某处声明一次,而不是请求内联。
不幸的是,内联和非内联是不可移植的。它由编译器编写者定义。一个好的经验法则是始终使每个内联,特别是所有本身只是调用函数的函数,内联,因为你消除了开销。任何低于三行线性代码的内容几乎都可以。但是如果你的代码中有一个循环,问题是编译器是否允许它内联,更重要的是,即使它做了你想要的,你会看到多少好处。
考虑一下这个内联代码:
inline int add(int a, int b) { return a + b; }
它不仅几乎与源代码中的原型一样小,而且内联代码生成的汇编语言也比对例程的调用要小。所以这段代码更小,更快。
而且,如果你碰巧传入了常量:
int c= add(5,4);
在编译时就解决了,没有代码。
在 gcc 中,我最近注意到即使我不内联代码,如果它是文件本地的,他们无论如何都会偷偷地内联它。只有当我在单独的源模块中声明该函数时,它们才不会优化调用。
另一方面,假设您在 1000 行代码中请求内联。即使你的编译器傻到可以配合它,你唯一节省的就是调用本身,代价是每次调用它时,编译器都必须将所有代码粘贴进去。如果你调用该代码 n 次,您的代码会按例程 * n 的大小增长。所以任何大于 10 行的东西都几乎不值得内联,除了只被调用很少次的特殊情况。这方面的一个例子可能是只有另外两个人调用的私有方法。
如果您请求内联包含循环的方法,则只有当它经常执行少量时才有意义。但是考虑一个迭代一百万次的循环。即使代码是内联的,花费在调用中的时间百分比也很小。因此,如果您有带有循环的方法,无论如何它们往往会更大,那么这些方法值得从头文件中删除,因为它们 a) 往往会被编译器拒绝为内联,并且 b) 即使它们是内联的,通常也是不会提供任何好处
【讨论】:
编译器必须将其视为内联请求——它可以忽略。在头文件中定义一些函数(例如空的虚拟析构函数)和一些必要的头文件定义(模板函数)有一些习惯用法,但除此之外,请参阅GotW #33 了解更多信息。
有些人注意到编译器甚至可能内联您从未要求过的函数,但我不确定这是否会破坏请求内联函数的目的。
【讨论】:
它确实是内联的——但是编译器可以忽略任何内联请求。
【讨论】:
这是对编译器的请求,它可以忽略。
【讨论】:
inline。
inline 请求一样。
2003 ISO C++ 标准说
7.1.2/2 带有内联的函数声明(8.3.5、9.3、11.4) 说明符声明内联 功能。内联说明符 向实现表明 函数的内联替换 呼叫点的身体是 优于通常的函数调用
机制。一个实现不是 需要执行此内联
在呼叫点替换; 但是,即使这个内联
替换被省略,其他 定义内联函数的规则 到 7.1.2 仍应得到尊重。7.1.2/3 在类定义中定义的函数是内联函数
功能。内联说明符应 没有出现在块作用域函数上 声明。7.1.2/4 应在
中的每个翻译单元中定义内联函数 它被使用并应具有 每个中的定义完全相同
案例(3.2)。 [注:调用 可能会遇到内联函数
在其定义出现之前 翻译单元。 ] 如果一个函数 声明了带有外部链接的 内联在一个翻译单元中,它 应在所有声明中内联 它所在的翻译单位 出现;不需要诊断。一个 带外部的内联函数 链接应具有相同的地址 所有翻译单元。一个静态的 外部内联中的局部变量
函数总是指同一个 目的。 an
中的字符串文字 extern 内联函数是一样的 不同翻译的对象
单位。
【讨论】:
有两件事不应该混为一谈:
【讨论】: