什么时候我应该写关键字内联的函数/方法在c++ ?
在看到一些答案后,一些相关的问题:
在c++中,什么时候我不应该为函数/方法写关键字“内联”? 什么时候编译器不知道什么时候使一个函数/方法'内联'? 当一个应用程序为一个函数/方法写“内联”时,它是否重要?
什么时候我应该写关键字内联的函数/方法在c++ ?
在看到一些答案后,一些相关的问题:
在c++中,什么时候我不应该为函数/方法写关键字“内联”? 什么时候编译器不知道什么时候使一个函数/方法'内联'? 当一个应用程序为一个函数/方法写“内联”时,它是否重要?
当前回答
实际上,几乎从来没有。你所做的只是建议编译器将给定的函数内联(例如,替换对该函数的所有调用/w它的函数体)。当然,这不能保证:编译器可能会忽略该指令。
编译器通常会很好地检测和优化这样的事情。
其他回答
F.5:如果一个函数非常小并且对时间要求很高,那么就内联声明它
原因:一些优化器在没有程序员提示的情况下很擅长内联,但不要依赖它。测量!在过去40年左右的时间里,我们一直被承诺在没有人类提示的情况下,编译器可以比人类更好地内联。我们还在等待。指定inline(在类定义中编写成员函数时显式或隐式)可以鼓励编译器更好地完成工作。
来源:https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html Rf-inline
有关示例和异常,请访问源代码(参见上面)。
一个用例可能发生在继承上。例如,如果以下所有情况都为真:
你有某个类的基类 基类需要是抽象的 基类除了析构函数之外没有纯虚方法 您不希望为基类创建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);
}
什么时候编译器不知道什么时候使一个函数/方法'内联'?
这取决于所使用的编译器。不要盲目相信现在的编译器比人类更了解如何内联,也不要因为性能原因而使用它,因为它是链接指令而不是优化提示。虽然我同意这些观点在意识形态上是正确的,但遇到现实可能是另一回事。
在阅读了多个线程之后,出于好奇,我尝试了内联对我正在工作的代码的影响,结果是我得到了GCC的可测量加速,而英特尔编译器的速度没有提高。
(更多细节:数学模拟与少数关键函数定义类之外,GCC 4.6.3 (g++ -O3), ICC 13.1.0 (icpc -O3);将内联添加到临界点导致GCC代码加速6%)。
因此,如果你将GCC 4.6限定为现代编译器,那么如果你编写CPU密集型任务,并且知道瓶颈在哪里,内联指令仍然很重要。
什么时候应该内联:
1.当人们想要避免调用函数时发生的开销,如参数传递,控制传递,控制返回等。
2.函数应该很小,经常被调用,并且内联是非常有利的,因为根据80-20规则,尽量使那些对程序性能有重大影响的函数内联。
正如我们所知,内联只是一个请求编译器类似于注册,它将花费你在对象代码大小。
天啊,我最讨厌的事之一。
内联更像静态或extern,而不是告诉编译器内联函数的指令。Extern, static, inline是链接指令,几乎只由链接器使用,而不是编译器。
据说,内联提示编译器,你认为函数应该内联。这在1998年可能是正确的,但十年后,编译器不需要这样的提示。更不用说,当涉及到优化代码时,人类通常是错误的,所以大多数编译器会忽略“提示”。
static - the variable/function name cannot be used in other translation units. Linker needs to make sure it doesn't accidentally use a statically defined variable/function from another translation unit. extern - use this variable/function name in this translation unit but don't complain if it isn't defined. The linker will sort it out and make sure all the code that tried to use some extern symbol has its address. inline - this function will be defined in multiple translation units, don't worry about it. The linker needs to make sure all translation units use a single instance of the variable/function.
注意:通常,将模板声明为内联是没有意义的,因为它们已经具有内联的链接语义。但是,模板的显式专门化和实例化需要内联使用。
具体问题解答:
When should I write the keyword 'inline' for a function/method in C++? Only when you want the function to be defined in a header. More exactly only when the function's definition can show up in multiple translation units. It's a good idea to define small (as in one liner) functions in the header file as it gives the compiler more information to work with while optimizing your code. It also increases compilation time. When should I not write the keyword 'inline' for a function/method in C++? Don't add inline just because you think your code will run faster if the compiler inlines it. When will the compiler not know when to make a function/method 'inline'? Generally, the compiler will be able to do this better than you. However, the compiler doesn't have the option to inline code if it doesn't have the function definition. In maximally optimized code usually all private methods are inlined whether you ask for it or not. As an aside to prevent inlining in GCC, use __attribute__(( noinline )), and in Visual Studio, use __declspec(noinline). Does it matter if an application is multithreaded when one writes 'inline' for a function/method? Multithreading doesn't affect inlining in any way.