ChatGPT解决这个技术问题 Extra ChatGPT

我什么时候应该为函数/方法编写关键字“内联”?

何时应该为 C++ 中的函数/方法编写关键字 inline

看到一些答案后,一些相关的问题:

什么时候不应该为 C++ 中的函数/方法编写关键字“内联”?

编译器何时不知道何时将函数/方法“内联”?

当为函数/方法编写“内联”时,应用程序是否是多线程的是否重要?

如果在标头中定义函数,则需要将其声明为内联。否则,您将收到有关函数的多个定义的链接器错误。
@Martin:除非它在类定义中,否则要挑剔。
@David:要格外挑剔,那只是因为这些函数被隐式标记为 inline (9.3/2)。
另请参阅 C++ 常见问题解答中的 Inline Functions。他们对内联有很好的处理。

L
L. F.

哦,伙计,我最讨厌的事情之一。

inline 更像是 staticextern,而不是告诉编译器内联函数的指令。 externstaticinline 是链接指令,几乎只由链接器使用,而不是编译器。

据说 inline 向编译器暗示您认为该函数应该被内联。这在 1998 年可能是正确的,但十年后编译器不需要这样的提示。更不用说在优化代码时人类通常是错误的,所以大多数编译器完全忽略了“提示”。

static - 变量/函数名称不能在其他翻译单元中使用。链接器需要确保它不会意外使用来自另一个翻译单元的静态定义的变量/函数。

extern - 在此翻译单元中使用此变量/函数名称,但如果未定义,请不要抱怨。链接器将对其进行排序,并确保所有尝试使用外部符号的代码都有其地址。

inline - 这个函数将在多个翻译单元中定义,不用担心。链接器需要确保所有翻译单元都使用变量/函数的单个实例。

注意: 通常,声明模板 inline 是没有意义的,因为它们已经具有 inline 的链接语义。但是,要使用模板 require inline 的显式特化和实例化。

您的问题的具体答案:

我什么时候应该为 C++ 中的函数/方法编写关键字“内联”?仅当您希望在标题中定义函数时。更准确地说,只有当函数的定义可以出现在多个翻译单元中时。在头文件中定义小(如在一个衬里)函数是一个好主意,因为它为编译器提供了更多信息以在优化代码时使用。它还增加了编译时间。

什么时候不应该为 C++ 中的函数/方法编写关键字“内联”?不要仅仅因为您认为如果编译器内联您的代码会运行得更快,就添加内联。

编译器何时不知道何时将函数/方法“内联”?一般来说,编译器会比你做得更好。但是,如果没有函数定义,编译器就没有内联代码的选项。在最大限度优化的代码中,无论您是否要求,通常所有私有方法都会被内联。为了防止在 GCC 中进行内联,请使用 __attribute__(( noinline )),而在 Visual Studio 中,请使用 __declspec(noinline)。

当为函数/方法编写“内联”时,应用程序是否是多线程的是否重要?多线程不会以任何方式影响内联。


+1 我在 ...(永远)中看到的对内联的最佳描述。我现在将扯掉你,并在我对 inline 关键字的所有解释中使用它。
这个答案让我有点困惑。您说了所有关于编译器能够更好地内联/不内联事物的内容。然后你说你应该在头文件中放置一个衬里/小函数,并且编译器不能在没有函数定义的情况下内联代码。这些是不是有点矛盾?为什么不把所有东西都放在 cpp 文件中,让编译器来决定呢?
编译器只会内联函数调用,其中定义在调用站点可用。将所有函数保留在 cpp 文件中会限制对该文件的内联。我建议在 .h 中内联定义小的 1 行,因为编译速度的成本可以忽略不计,并且几乎可以保证编译器会内联调用。我关于编译器内联的观点是,它是优化黑艺术的移植,在这方面你的编译器比你好得多。
每当我读到关于互联网累积知识的内容时,我都会想起约翰·劳顿的名言:The irony of the Information Age is that it has given new respectability to uninformed opinion.
“所以大多数编译器完全忽略了‘提示’。”这显然是错误的。至少 Clang 和 GCC 使用 inline 关键字作为内联的提示:blog.tartanllama.xyz/inline-hints
J
Jacob

我想通过一个令人信服的例子来为这个线程中的所有重要答案做出贡献,以消除任何剩余的误解。

给定两个源文件,例如:

inline111.cpp: #include void bar();内联 int fun() { 返回 111; } int main() { std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun;酒吧(); }

inline222.cpp: #include inline int fun() { return 222; } void bar() { std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun; }

案例 A:编译:g++ -std=c++11 inline111.cpp inline222.cpp 输出:inline111: fun() = 111, &fun = 0x4029a0 inline222: fun() = 111, &fun = 0x4029a0 讨论:即使你也应该这样做具有相同的内联函数定义,如果不是这种情况,C++ 编译器不会标记它(实际上,由于单独编译它无法检查它)。确保这一点是您自己的责任!链接器不会抱怨单一定义规则,因为 fun() 被声明为内联。但是,因为 inline111.cpp 是编译器处理的第一个翻译单元(实际上调用 fun()),所以编译器会在 inline111.cpp 中的第一次调用遇到时实例化 fun()。如果编译器决定不扩展 fun() 从程序中的任何其他位置调用它(例如从 inline222.cpp),对 fun() 的调用将始终链接到它从 inline111.cpp 生成的实例(对 fun() 的调用) 内 inline222.cpp 也可能在该翻译单元中生成一个实例,但它将保持未链接)。事实上,从相同的 &fun = 0x4029a0 打印输出中可以明显看出这一点。最后,尽管向编译器提出了实际扩展单行 fun() 的内联建议,但它完全忽略了您的建议,这很清楚,因为两行中的 fun() = 111。

即使您应该对内联函数有相同的定义,如果不是这种情况,C++ 编译器也不会标记它(实际上,由于单独编译,它无法检查它)。确保这一点是您自己的责任!

链接器不会抱怨单一定义规则,因为 fun() 被声明为内联。但是,因为 inline111.cpp 是编译器处理的第一个翻译单元(实际上调用 fun()),所以编译器会在 inline111.cpp 中的第一次调用遇到时实例化 fun()。如果编译器决定不扩展 fun() 从程序中的任何其他位置调用它(例如从 inline222.cpp),对 fun() 的调用将始终链接到它从 inline111.cpp 生成的实例(对 fun() 的调用) 内 inline222.cpp 也可能在该翻译单元中生成一个实例,但它将保持未链接)。事实上,从相同的 &fun = 0x4029a0 打印输出中可以明显看出这一点。

最后,尽管向编译器提出了实际扩展单行 fun() 的内联建议,但它完全忽略了您的建议,这很清楚,因为两行中的 fun() = 111。

案例B:编译(注意倒序):g++ -std=c++11 inline222.cpp inline111.cpp 输出:inline111: fun() = 222, &fun = 0x402980 inline222: fun() = 222, &fun = 0x402980 讨论:这个案例断言了案例 A 中讨论过的内容。请注意重要的一点,如果您注释掉 inline222.cpp 中对 fun() 的实际调用(例如,完全注释掉 inline222.cpp 中的 cout 语句),那么尽管编译翻译单元的顺序,fun() 将在 inline111.cpp 中第一次调用时被实例化,导致案例 B 的打印输出为 inline111:fun() = 111, &fun = 0x402980。

这个案例断言了案例 A 中讨论的内容。

请注意重要的一点,如果您注释掉 inline222.cpp 中对 fun() 的实际调用(例如,完全注释掉 inline222.cpp 中的 cout-statement),那么,尽管您的翻译单元的编译顺序不同,但 fun() 将是在 inline111.cpp 中第一次调用遇到时实例化,导致案例 B 的打印输出为 inline111:fun() = 111, &fun = 0x402980。

案例 C:编译(注意 -O2):g++ -std=c++11 -O2 inline222.cpp inline111.cpp 或 g++ -std=c++11 -O2 inline111.cpp inline222.cpp 输出:inline111: fun() = 111, &fun = 0x402900 inline222: fun() = 222, &fun = 0x402900 讨论:正如这里所描述的,-O2 优化鼓励编译器实际扩展可以内联的函数(还要注意 -fno-inline 是默认的,没有优化选项)。从这里的输出可以明显看出,fun() 实际上已经被内联扩展(根据它在特定翻译单元中的定义),导致两个不同的 fun() 输出。尽管如此,仍然只有一个全局链接的 fun() 实例(根据标准的要求),从相同的 &fun 打印输出中可以看出这一点。

正如这里所描述的,-O2 优化鼓励编译器实际扩展可以内联的函数(还要注意 -fno-inline 是默认的,没有优化选项)。从这里的输出可以明显看出,fun() 实际上已经被内联扩展(根据它在特定翻译单元中的定义),导致两个不同的 fun() 输出。尽管如此,仍然只有一个全局链接的 fun() 实例(根据标准的要求),从相同的 &fun 打印输出中可以看出这一点。


您的回答是一篇说明性文章,说明了为什么语言使此类 inline 函数成为未定义的行为。
您还应该添加编译和链接是分开的情况,每个 .cpp 都是它自己的翻译单元。最好为启用/禁用的 -flto 添加案例。
C++ 参考明确指出“如果具有外部链接的内联函数或变量(自 C++17 起)在不同的翻译单元中定义不同,则行为未定义。”。因此,您编写的内容是 GCC 特定的,因为它是编排编译和链接过程的副作用。另外,请注意,这可能因版本而异。
我知道 inline 告诉链接器允许符号冲突(坚持来自第一个翻译单元的符号),但是为什么不需要测试符号的等价性呢?该标准应要求编译器为所有内联函数提供 LTO 信息,并强制进行此类检查!
B
BostonLogan

在进行模板特化时,您仍然需要显式内联您的函数(如果特化在 .h 文件中)


A
Aric TenEyck

1)如今,几乎从来没有。如果内联函数是个好主意,编译器会在没有你帮助的情况下完成它。

2) 总是。见#1。

(编辑以反映您将问题分为两个问题......)


是的。内联只是对编译器的提示,可以随意忽略你。如今,编译器可能比程序员更清楚哪些函数最好内联。
是的,但它不太相关 - 对于要内联的函数,它的主体必须在同一个编译单元中(例如,在标头中)。这在 C 程序中不太常见。
定义非成员函数模板(又名非静态函数模板)不需要内联。见一个定义规则(3.2/5)。
-1:仍然需要 inline,例如在头文件中定义一个函数(这是在多个编译单元中内联此类函数所必需的)。
@Étienne 这是特定于实现的。根据标准,有一个定义规则,这意味着如果您天真地将函数定义包含在多个翻译单元中,您将得到一个错误。但是,如果该函数具有 inline 说明符,则链接器会自动将其实例合并为一个,并且不使用 ODR。
J
Johannes Schaub - litb

什么时候不应该为 C++ 中的函数/方法编写关键字“内联”?

如果函数在标头中声明并在 .cpp 文件中定义,则您应该编写关键字。

编译器何时不知道何时将函数/方法“内联”?

没有这种情况。编译器不能使函数内联。它所能做的就是内联对函数的部分或全部调用。如果它没有函数的代码,它就不能这样做(在这种情况下,如果它能够这样做,链接器需要这样做)。

当为函数/方法编写“内联”时,应用程序是否是多线程的是否重要?

不,这根本不重要。


在某些情况下,在 .cpp 文件中使用内联是合适的。例如,将优化应用于完全特定于实现的代码。
@RobinDavies 更新了答案。看来你误解了我想写的内容。
@JohannesSchaub-litb 如果函数在标头中声明并在 .cpp 文件中定义,则不应使用 inline 关键字。deft_code(967 次投票和接受的答案)提及与此相反您应该只在函数的定义可以显示在多个翻译单元中时才使用 inline 关键字所以我通过在头文件中使用关键字 inline 声明函数并在 .cpp 中定义它来检查它文件,它会给出错误 undefined reference。所以你是对的。现在你也提到了,........继续下一条评论
@JohannesSchaub-litb ........ 编译器无法使用多个翻译单元中的函数代码,因此无法将它们内联,因此它是链接器的工作。从这个意义上说,deft_code 表示 ,因此您应该使用 inline 关键字,以便为编译器提供更多信息。使用优化代码 所以他的措辞在这里也很有意义,但是当我尝试在前面提到的代码中使用它时会出错。所以我觉得你的两个陈述是相互对立的,但它们都是有道理的,但是当我实际检查你的陈述是真的时,请你对此有所了解。
m
meda beda

编译器何时不知道何时将函数/方法“内联”?

这取决于使用的编译器。不要盲目相信现在的编译器比人类更了解如何内联,并且出于性能原因你永远不应该使用它,因为它是链接指令而不是优化提示。虽然我同意这些论点在意识形态上是否正确,但遇到现实可能是另一回事。

在阅读了多个线程之后,我出于好奇尝试了内联对我正在工作的代码的影响,结果是我对 GCC 获得了可测量的加速,而对英特尔编译器没有加速。

(更多细节:在类之外定义了少量关键函数的数学模拟,GCC 4.6.3 (g++ -O3),ICC 13.1.0 (icpc -O3);在关键点添加内联导致 GCC 代码加速 + 6%)。

因此,如果您将 GCC 4.6 限定为现代编译器,那么如果您编写 CPU 密集型任务并且知道瓶颈到底在哪里,那么 inline 指令仍然很重要。


我希望看到更多证据来支持你的说法。请提供您正在测试的代码以及带有和不带有 inline 关键字的汇编程序输出。任何数量的东西都可以为您带来性能优势。
终于有人不仅重复别人所说的,而且确实验证了这些陈述。 Gcc 确实仍然将 inline 关键字视为提示(我认为 clang 完全忽略了它)。
@void.pointer:为什么这很难相信?如果优化器已经很完美,那么新版本就无法提高程序性能。但他们经常这样做。
D
DarkSquid

实际上,几乎从来没有。您所做的只是建议编译器将给定的函数内联(例如,替换对该函数的所有调用/w 它的主体)。当然,不能保证:编译器可能会忽略该指令。

编译器通常会很好地检测+优化这样的事情。


问题是 inline 在 C++ 中具有 语义 差异(例如处理多个定义的方式),这在某些情况下很重要(例如模板)。
inline 用于解决符号具有多个定义的情况。然而,模板已经由语言处理。一个例外是不再具有任何模板参数的专用模板函数 (template<>)。这些被视为更像函数而不是模板,因此需要 inline 关键字才能链接。
J
Jedzia

默认情况下,gcc 在未启用优化的情况下编译时不会内联任何函数。我不了解 Visual Studio – deft_code

我通过使用 /FAcs 编译并查看汇编代码检查了 Visual Studio 9 (15.00.30729.01) 的情况:编译器在调试模式下未启用优化的情况下产生对成员函数的调用。即使函数用 __forceinline 标记,也不会生成内联运行时代码。


启用 /Wall 以告知哪些函数标记为内联但实际上并未内联
K
Kayaalp

F.5:如果函数非常小且时间紧迫,则将其声明为内联

原因:一些优化器擅长在没有程序员提示的情况下进行内联,但不要依赖它。措施!在过去 40 年左右的时间里,我们得到承诺,编译器可以在没有人类提示的情况下比人类更好地内联。我们还在等。指定内联(在类定义中编写成员函数时显式或隐式)鼓励编译器做得更好。

来源:https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html#Rf-inline

有关示例和例外情况,请转到来源(见上文)。


O
Oğuzhan Türk

一个用例可能发生在继承上。例如,如果以下所有情况都为真:

你有某个类的基类

基类必须是抽象的

基类除了析构函数外没有纯虚方法

您不想为基类创建 cpp 文件,因为徒劳

然后你必须定义析构函数;否则,您将遇到一些 undefined referance 链接器错误。此外,您不仅要定义,还要使用 inline 关键字定义析构函数;否则,您将有 multiple definition 个链接器错误。

这可能发生在一些只包含静态方法或编写基础异常类等的辅助类上。

我们举个例子:

基数.h:

class Base {
public:
    Base(SomeElementType someElement) noexcept : _someElement(std::move(someElement)) {}

    virtual ~Base() = 0;

protected:
    SomeElementType _someElement;
}

inline Base::~Base() = default;

派生1.h:

#include "Base.h"

class Derived1 : public Base {
public:
    Derived1(SomeElementType someElement) noexcept : Base(std::move(someElement)) {}

    void DoSomething1() const;
}

派生1.cpp:

#include "Derived1.h"

void Derived1::DoSomething1() const {
    // use _someElement 
}

派生2.h:

#include "Base.h"

class Derived2 : public Base {
public:
    Derived2(SomeElementType someElement) noexcept : Base(std::move(someElement)) {}

    void DoSomething2() const;
}

派生2.cpp:

#include "Derived2.h"

void Derived2::DoSomething2() const {
    // use _someElement 
}

通常,抽象类除了构造函数或析构函数之外还有一些纯虚方法。因此,您不必将基类的虚拟析构函数的声明和定义分开,您可以在类声明上写 virtual ~Base() = default;。但是,在我们的案例中,情况并非如此。

据我所知,MSVC 允许您在类声明中编写类似的内容:virtual ~Base() = 0 {}。因此,您不需要使用 inline 关键字将 decleration 和定义分开。但它只适用于 MSVC 编译器。

现实世界的例子:

BaseException.h:

#pragma once

#include <string>

class BaseException : public std::exception {
public:
    BaseException(std::string message) noexcept : message(std::move(message)) {}
    virtual char const* what() const noexcept { return message.c_str(); }

    virtual ~BaseException() = 0;

private:
    std::string message;
};

inline BaseException::~BaseException() = default;

SomeException.h:

#pragma once

#include "BaseException.h"

class SomeException : public BaseException {
public:
    SomeException(std::string message) noexcept : BaseException(std::move(message)) {}
};

SomeOtherException.h:

#pragma once

#include "BaseException.h"

class SomeOtherException : public BaseException {
public:
    SomeOtherException(std::string message) noexcept : BaseException(std::move(message)) {}
};

主.cpp:

#include <SomeException.h>
#include <SomeOtherException.h>

#include <iostream>

using namespace std;

static int DoSomething(int argc) {
    try {
        switch (argc) {
        case 0:
            throw SomeException("some");
        case 1:
            throw SomeOtherException("some other");
        default:
            return 0;
        }
    }
    catch (const exception& ex) {
        cout << ex.what() << endl;
        return 1;
    }
}

int main(int argc, char**) {
    return DoSomething(argc);
}

C
Community

除非您正在编写库或有特殊原因,否则您可以忘记 inline 并改用 链接时间优化。它消除了函数定义必须在标头中才能考虑跨编译单元内联的要求,这正是 inline 所允许的。

(但请参阅 Is there any reason why not to use link time optimization?


L
Lewis Kelsey

C++ 内联与 C inline 完全不同。

#include <iostream>
extern inline int i[];
int i [5];
struct c {
  int function (){return 1;} // implicitly inline
  static inline int j = 3; // explicitly inline
  static int k; // without inline, a static member has to be defined out of line
  static int f (){return 1;} // but a static method does not // implicitly inline
};

extern inline int b;
int b=3;
int c::k = 3; // when a static member is defined out of line it cannot have a static
              // specifier and if it doesn't have an `inline` specifier in the
              // declaration or on the definition then it is not inline and always
              // emits a strong global symbol in the translation unit

int main() {
  c j;
  std::cout << i;
}

inline 本身会影响编译器、汇编器和链接器。它是对编译器的一个指令,如果它在翻译单元中使用,则只为这个函数/数据发出一个符号,如果是,那么就像类方法一样,告诉汇编器将它们存储在 .section .text.c::function(),"axG",@progbits,c::function(),comdat 或 {3 部分} 用于未初始化数据或 .section .data.b,"awG",@progbits,b,comdat 用于初始化数据。模板实例化也在它们自己的 comdat 组中。

这在 .section name, "flags"MG, @type, entsize, GroupName[, linkage] 之后。例如,部分名称是 .text.c::function()axG 表示该部分是可分配的、可执行的并且在一个组中,即将指定一个组名(并且没有 M 标志,因此不会指定 entsize); @progbits 表示该部分包含数据且不为空白; c::function() 是组名,并且该组具有 comdat 链接,这意味着在所有目标文件中,遇到带有该组名并带有 comdat 标记的所有部分都将从最终可执行文件中删除,除了 1 即编译器确保存在翻译单元中只有一个定义,然后告诉汇编器将其放在目标文件中自己的组中(1 组中的 1 节),然后链接器将确保如果任何目标文件具有同名的组,然后只在最终的 .exe 中包含一个。 inline 和不使用 inline 之间的区别现在对汇编器可见,因此链接器也可以看到,因为由于它们的指令,它没有被汇编器存储在常规的 .data.text 等中。只有具有外部链接的内联符号才会被赋予这样的外部 comdat 链接——静态链接(本地)符号不需要进入 comdat 组。

inline 在类中的非静态方法声明上,如果方法被离线定义,则使方法内联,这将防止在翻译单元中未引用该方法时在翻译单元中发出该方法。将 inline 放在行外定义上可以达到相同的效果。当一个方法在没有 inline 说明符的情况下被离线定义并且类中的声明不是 inline 时,它将始终在翻译单元中为该方法发出一个符号,因为它将具有外部链接而不是比外部 comdat 链接。如果该方法在类中定义,那么它是隐式的 inline,这给它提供了外部 comdat 链接而不是外部链接。

static inline 对类中的成员(与方法相反)使其成为 static 成员(不指代其链接——它具有其类的链接,可能是外部的)。 static inline 还允许在类中定义类的 static 成员,而不是需要在类中声明然后在外线定义(在定义中没有 static,这是不允许的-fpermissive)。 *static inline* 还使成员 inline 而不是 static inline - inline 表示仅在翻译单元中引用定义时才发出定义。以前,您必须在外联定义上指定 inline 才能使成员 inline

由于类中可以定义static方法,所以static inline对类中定义的static方法没有影响,它始终具有外部链接,是静态方法,是inline。如果它的定义不符合规定,则必须使用 inline 使其成为 inline(即提供给外部 comdat 链接而不仅仅是外部链接),并且 static 仍然不能使用。

文件范围内的 static inline 仅影响编译器。这对编译器意味着:只有在翻译单元中使用此函数/数据时才发出一个符号,并将其作为常规静态符号(存储在 .text /.data 中,而不使用 .globl 指令)。对于汇编程序来说,现在 staticstatic inline 之间没有区别。与 inline 的其他形式一样,它不能用于类型 class,但可以用于该类类型的对象。这种形式的 static inline 也不能用于函数的成员或方法,它总是被视为 inline,因为 static 表示类中的其他内容(这意味着该类充当范围而不是而不是作为对象的成员或方法使用)。

extern inline 是一个声明,意味着您必须在翻译单元中定义此符号,如果它被引用或抛出编译器错误;如果已定义,则将其视为常规 inline,对于汇编器和链接器,extern inlineinline 之间没有区别,因此这只是编译器保护。

extern inline int i[];
extern int i[]; //allowed repetition of declaration with incomplete type, inherits inline property
extern int i[5]; //declaration now has complete type
extern int i[5]; //allowed redeclaration if it is the same complete type or has not yet been completed
extern int i[6]; //error, redeclaration with different complete type
int i[5]; //definition, must have complete type and same complete type as the declaration if there is a declaration with a complete type

上面没有错误行的全部内容折叠为 inline int i[5]。显然,如果您执行 extern inline int i[] = {5};,那么 extern 将被忽略,因为通过分配进行了显式定义。

我认为在没有 -fpermissivestatic 外线定义中不允许 static 的原因是因为它暗示静态引用 static 链接,因为程序员并没有立即明白它是某个类的成员,或者该类是否具有 ,其中 static 表示不同的东西。 -fpermissive 忽略了外联定义中的 static 说明符,它没有任何意义。在一个简单整数的情况下,k 不能在命名空间之外定义,如果 c 是一个命名空间,但如果 k 是一个函数,那么就无法从行中明显看出的代码,无论是名称空间中具有 static 链接的函数的外线定义,还是具有外部链接的静态成员的外线定义,都可能给程序员/读者带来错误的印象编码。

对于本地类,成员/方法上的 inline 将导致编译器错误并且成员和方法没有链接。

对于命名空间上的 inline,请参阅 thisthis


S
Sheetal

inline 关键字要求编译器将函数调用替换为函数体,它首先计算表达式然后传递。它减少了函数调用开销,因为不需要存储返回地址,函数不需要堆栈内存论据。

何时使用:

提高性能 减少调用开销。由于这只是对编译器的请求,因此某些函数不会被内联 *大函数函数具有太多条件参数递归代码和带有循环的代码等。


知道事实并非如此,这可能会让您受益。优化级别 -O0 到 -Ofast 决定了函数是否内联。无论您是否在 C 和 C++ 中使用 inline,常规编译中的内联 (-O0) 都不会内联函数。 C 内联:stackoverflow.com/a/62287072/7194773 C++ 内联:stackoverflow.com/a/62230963/7194773
J
Jeremy Morgan

你想把它放在最开始,在返回类型之前。但是大多数编译器都忽略了它。如果它被定义,并且它有一个更小的代码块,大多数编译器无论如何都会认为它是内联的。


w
wallyk

开发和调试代码时,请忽略 inline。它使调试复杂化。

添加它们的主要原因是帮助优化生成的代码。通常,这会以增加的代码空间换取速度,但有时 inline 会同时节省代码空间和执行时间。

在算法完成之前扩展这种关于性能优化的想法是premature optimization


inline 函数通常不会内联,除非使用优化进行编译,因此它们不会以任何方式影响调试。请记住,这是一个提示,而不是一个要求。
默认情况下,gcc 在未启用优化的情况下编译时不会内联任何函数。我不知道视觉工作室
我在一个启用了调试的巨大 g++ 项目上工作。也许其他选项阻止了它,但 inline 函数是内联的。在它们中设置有意义的断点是不可能的。
启用调试不会停止 gcc 中的内联。如果启用了任何优化(-O1 或更高),则 gcc 将尝试内联最明显的情况。传统上,GDB 很难使用断点和构造函数,尤其是内联构造函数。但是,这已在最近的版本中得到修复(至少 6.7,也许更快)。
添加 inline 不会改善现代编译器上的代码,它可以自行判断是否内联。
B
BenMorel

什么时候应该内联:

1.当想要避免调用函数时发生的事情的开销,如参数传递、控制转移、控制返回等。

2.函数要小,经常调用,内联是非常有利的,因为按照80-20规则,尽量将那些对程序性能有重大影响的函数内联。

正如我们所知,内联只是对编译器的请求,类似于寄存器,它会花费你的对象代码大小。


“内联只是对类似于注册的编译器的请求”它们是相似的,因为它们都不是请求或与优化无关。 inline 已失去其作为优化提示的地位,并且大多数编译器仅使用它来允许多个定义 - 正如 IMO 应有的那样。更重要的是,自 C++11 以来,register 已完全被弃用,因为它先前的含义是“我比编译器更了解如何优化”:它现在只是一个没有当前含义的保留字。
@underscore_d:Gcc 在某种程度上仍然在听 inline