什么时候我应该写关键字内联的函数/方法在c++ ?
在看到一些答案后,一些相关的问题:
在c++中,什么时候我不应该为函数/方法写关键字“内联”? 什么时候编译器不知道什么时候使一个函数/方法'内联'? 当一个应用程序为一个函数/方法写“内联”时,它是否重要?
什么时候我应该写关键字内联的函数/方法在c++ ?
在看到一些答案后,一些相关的问题:
在c++中,什么时候我不应该为函数/方法写关键字“内联”? 什么时候编译器不知道什么时候使一个函数/方法'内联'? 当一个应用程序为一个函数/方法写“内联”时,它是否重要?
当前回答
一个用例可能发生在继承上。例如,如果以下所有情况都为真:
你有某个类的基类 基类需要是抽象的 基类除了析构函数之外没有纯虚方法 您不希望为基类创建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);
}
其他回答
在进行模板特化时,仍然需要显式内联函数(如果特化在.h文件中)
Inline关键字请求编译器用函数体替换函数调用,它首先计算表达式,然后传递。它减少了函数调用开销,因为不需要存储返回地址,函数参数也不需要堆栈内存。
使用时间:
提高绩效 减少呼叫开销。 因为它只是对编译器的请求,所以某些函数不会被内联 *大功能 有太多条件参数的函数 递归代码和带有循环的代码等等。
什么时候应该内联:
1.当人们想要避免调用函数时发生的开销,如参数传递,控制传递,控制返回等。
2.函数应该很小,经常被调用,并且内联是非常有利的,因为根据80-20规则,尽量使那些对程序性能有重大影响的函数内联。
正如我们所知,内联只是一个请求编译器类似于注册,它将花费你在对象代码大小。
在c++中,什么时候我不应该为函数/方法写关键字“内联”?
如果函数在头文件中声明,并在.cpp文件中定义,则不应编写关键字。
什么时候编译器不知道什么时候使一个函数/方法'内联'?
没有这种情况。编译器不能使函数内联。它所能做的就是内联对函数的部分或所有调用。如果它没有函数的代码,它就不能这样做(在这种情况下,链接器需要这样做,如果它能够这样做的话)。
当一个应用程序为一个函数/方法写“内联”时,它是否重要?
不,那完全不重要。
一个用例可能发生在继承上。例如,如果以下所有情况都为真:
你有某个类的基类 基类需要是抽象的 基类除了析构函数之外没有纯虚方法 您不希望为基类创建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);
}