什么时候我应该写关键字内联的函数/方法在c++ ?
在看到一些答案后,一些相关的问题:
在c++中,什么时候我不应该为函数/方法写关键字“内联”? 什么时候编译器不知道什么时候使一个函数/方法'内联'? 当一个应用程序为一个函数/方法写“内联”时,它是否重要?
什么时候我应该写关键字内联的函数/方法在c++ ?
在看到一些答案后,一些相关的问题:
在c++中,什么时候我不应该为函数/方法写关键字“内联”? 什么时候编译器不知道什么时候使一个函数/方法'内联'? 当一个应用程序为一个函数/方法写“内联”时,它是否重要?
当前回答
在开发和调试代码时,不要使用内联。这会使调试复杂化。
添加它们的主要原因是为了帮助优化生成的代码。通常,这是以增加的代码空间换取速度,但有时内联可以同时节省代码空间和执行时间。
在算法完成之前将这种思想扩展到性能优化是不成熟的优化。
其他回答
1)如今,几乎从来没有。如果内联一个函数是个好主意,编译器会在没有你帮助的情况下完成它。
2)。看到# 1。
(经过编辑,反映出你把问题分成了两个问题……)
除非您正在编写一个库或有特殊的原因,否则您可以忘记内联,而是使用链接时间优化。它消除了函数定义必须在头文件中才能考虑跨编译单元进行内联的要求,这正是内联所允许的。
(但请参阅为什么不使用链接时间优化?)
什么时候编译器不知道什么时候使一个函数/方法'内联'?
这取决于所使用的编译器。不要盲目相信现在的编译器比人类更了解如何内联,也不要因为性能原因而使用它,因为它是链接指令而不是优化提示。虽然我同意这些观点在意识形态上是正确的,但遇到现实可能是另一回事。
在阅读了多个线程之后,出于好奇,我尝试了内联对我正在工作的代码的影响,结果是我得到了GCC的可测量加速,而英特尔编译器的速度没有提高。
(更多细节:数学模拟与少数关键函数定义类之外,GCC 4.6.3 (g++ -O3), ICC 13.1.0 (icpc -O3);将内联添加到临界点导致GCC代码加速6%)。
因此,如果你将GCC 4.6限定为现代编译器,那么如果你编写CPU密集型任务,并且知道瓶颈在哪里,内联指令仍然很重要。
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);
}