什么时候我应该写关键字内联的函数/方法在c++ ?
在看到一些答案后,一些相关的问题:
在c++中,什么时候我不应该为函数/方法写关键字“内联”? 什么时候编译器不知道什么时候使一个函数/方法'内联'? 当一个应用程序为一个函数/方法写“内联”时,它是否重要?
什么时候我应该写关键字内联的函数/方法在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
有关示例和异常,请访问源代码(参见上面)。