什么时候我应该写关键字内联的函数/方法在c++ ?

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

在c++中,什么时候我不应该为函数/方法写关键字“内联”? 什么时候编译器不知道什么时候使一个函数/方法'内联'? 当一个应用程序为一个函数/方法写“内联”时,它是否重要?


当前回答

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

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

其他回答

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

你有某个类的基类 基类需要是抽象的 基类除了析构函数之外没有纯虚方法 您不希望为基类创建CPP文件,因为这是徒劳的

然后你必须定义析构函数;否则,你会有一些未定义的引用链接错误。此外,你不仅要定义,还要用inline关键字定义析构函数;否则,您将有多个定义链接错误。

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

让我们举个例子:

Base.h:

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

    virtual ~Base() = 0;

protected:
    SomeElementType _someElement;
}

inline Base::~Base() = default;

Derived1.h:

#include "Base.h"

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

    void DoSomething1() const;
}

Derived1.cpp:

#include "Derived1.h"

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

Derived2.h:

#include "Base.h"

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

    void DoSomething2() const;
}

Derived2.cpp:

#include "Derived2.h"

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

通常,抽象类有一些纯虚方法,而不是构造函数或析构函数。因此,你不必分离基类的虚析构函数的声明和定义,你可以只写virtual ~ base () = default;关于类声明。然而,在我们的案例中,情况并非如此。

据我所知,MSVC允许你在类声明上写这样的东西:virtual ~Base() = 0{}。所以你不需要用内联关键字分离声明和定义。但它将只与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)) {}
};

main.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);
}

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

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

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

编译时,GCC默认不内联任何函数 启用优化。我不知道visual studio - deft_code

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

F.5:如果一个函数非常小并且对时间要求很高,那么就内联声明它

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

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

有关示例和异常,请访问源代码(参见上面)。