在c++的头文件中编写函数定义

时间:2021-03-22 15:07:30

I have a class which has many small functions. By small functions, I mean functions that doesn't do any processing but just return a literal value. Something like:

我有一个有许多小函数的类。所谓小函数,我指的是不做任何处理但只返回一个文字值的函数。喜欢的东西:

string Foo::method() const{
    return "A";
}

I have created a header file "Foo.h" and source file "Foo.cpp". But since the function is very small, I am thinking about putting it in the header file itself. I have the following questions:

我创建了一个头文件“Foo”。h和源文件“Foo.cpp”。但是由于这个函数很小,所以我想把它放在头文件中。我有以下问题:

  1. Is there any performance or other issues if I put these function definition in header file? I will have many functions like this.
  2. 如果我把这些函数定义放在头文件中,会有什么性能或其他问题吗?我会有很多这样的函数。
  3. My understanding is when the compilation is done, compiler will expand the header file and place it where it is included. Is that correct?
  4. 我的理解是编译完成后,编译器将展开头文件并将其放置在包含它的地方。那是正确的吗?

7 个解决方案

#1


62  

If the function is small (the chance you would change it often is low), and if the function can be put into the header without including myriads of other headers (because your function depends on them), it is perfectly valid to do so. If you declare them extern inline, then the compiler is required to give it the same address for every compilation unit:

如果函数很小(更改它的可能性很小),并且如果可以将函数放入header中,而不包含其他的header(因为您的函数依赖于它们),那么这样做是完全有效的。如果您以内联方式声明它们,则要求编译器为每个编译单元提供相同的地址:

headera.h:

headera.h:

inline string method() {
    return something;
}

Member functions are implicit inline provided they are defined inside their class. The same stuff is true for them true: If they can be put into the header without hassle, you can indeed do so.

成员函数是隐式内联的,只要它们是在类中定义的。同样的事情对他们来说也是正确的:如果他们可以毫不费力地放入标题,你确实可以这么做。

Because the code of the function is put into the header and visible, the compiler is able to inline calls to them, that is, putting code of the function directly at the call site (not so much because you put inline before it, but more because the compiler decides that way, though. Putting inline only is a hint to the compiler regarding that). That can result in a performance improvement, because the compiler now sees where arguments match variables local to the function, and where argument doesn't alias each other - and last but not least, function frame allocation isn't needed anymore.

因为函数的代码放到页眉和可见的,编译器可以内联调用它们,也就是说,把函数的代码直接调用站点(不是因为你把内联之前,但更多的,因为编译器决定,。只放置内联是对编译器的一个提示)。这可以提高性能,因为编译器现在看到参数与函数本地变量匹配的地方,以及参数之间不存在别名的地方——最后但同样重要的是,不再需要函数框架分配。

My understanding is when the compilation is done, compiler will expand the header file and place it where it is included. Is that correct?

我的理解是编译完成后,编译器将展开头文件并将其放置在包含它的地方。那是正确的吗?

Yes, that is correct. The function will be defined in every place where you include its header. The compiler will care about putting only one instance of it into the resulting program, by eliminating the others.

是的,这是正确的。函数将在包含它的头的每个地方定义。编译器只关心将它的一个实例放入结果程序中,消除其他实例。

#2


12  

Depending on your compiler and it's settings it may do any of the following:

取决于你的编译器和它的设置,它可以做以下任何一种:

  • It may ignore the inline keyword (it is just a hint to the compiler, not a command) and generate stand-alone functions. It may do this if your functions exceed a compiler-dependent complexity threshold. e.g. too many nested loops.
  • 它可以忽略inline关键字(它只是对编译器的提示,而不是命令),并生成独立函数。如果您的函数超过了依赖于编译器的复杂性阈值,那么可以这样做。太多的嵌套循环。
  • It may decide than your stand-alone function is a good candidate for inline expansion.
  • 它可能会决定您的独立函数是否适合内联扩展。

In many cases, the compiler is in a much better position to determine if a function should be inlined than you are, so there is no point in second-guessing it. I like to use implicit inlining when a class has many small functions only because it's convenient to have the implementation right there in the class. This doesn't work so well for larger functions.

在许多情况下,编译器可以更好地确定一个函数是否应该内联,因此没有必要对它进行事后批评。当一个类有许多小函数时,我喜欢使用隐式内联,因为在类中有实现是很方便的。对于更大的函数来说,这不是很好。

The other thing to keep in mind is that if you are exporting a class in a DLL/shared library (not a good idea IMHO, but people do it anyway) you need to be really careful with inline functions. If the compiler that built the DLL decides a function should be inlined you have a couple of potential problems:

另一件需要记住的事情是,如果在DLL/共享库中导出一个类(不是个好主意,但人们还是会这么做),那么您需要对内联函数非常小心。如果构建DLL的编译器认为一个函数应该内联,那么您就会遇到一些潜在的问题:

  1. The compiler building the program using the DLL might decide to not inline the function so it will generate a symbol reference to a function that doesn't exist and the DLL will not load.
  2. 使用DLL构建程序的编译器可能决定不内联该函数,因此它将生成一个对不存在的函数的符号引用,并且DLL将不会加载。
  3. If you update the DLL and change the inlined function, the client program will still be using the old version of that function since the function got inlined into the client code.
  4. 如果您更新DLL并更改内联函数,客户端程序将仍然使用该函数的旧版本,因为该函数已内联到客户端代码中。

#3


4  

There will be an increase in performance because implementation in header files are implicitly inlined. As you mentioned your functions are small, inline operation will be so beneficial for you IMHO.

由于头文件中的实现是隐式内联的,因此性能会有所提高。正如您提到的,您的函数很小,内联操作对您非常有益。

What you say about compiler is also true.There is no difference for compiler—other than inlining—between code in header file or .cpp file.

你说的编译器也是正确的。除了在头文件或.cpp文件中的代码之间进行内联之外,编译器没有任何区别。

#4


2  

  1. If your functions are that simple, make them inline, and you'll have to stick them in the header file anyway. Other than that, any conventions are just that - conventions.

    如果您的函数非常简单,请将它们内联,并且您将不得不将它们放在头文件中。除此之外,任何约定都只是那个约定。

  2. Yes, the compiler does expand the header file where it encounters the #include statements.

    是的,编译器确实扩展了遇到#include语句的头文件。

#5


1  

It depends on the coding standards that apply in your case but:

这取决于适用于您的情况的编码标准,但是:

Small functions without loops and anything else should be inlined for better performance (but slightly larger code - important for some constrained or embedded applications).

没有循环和其他任何东西的小函数应该内联以获得更好的性能(但是稍微大一点的代码——对于某些受限或嵌入式应用程序很重要)。

If you have the body of the function in the header you will have it by default inline(d) (which is a good thing when it comes to speed).

如果在header中有函数的主体,那么默认情况下它是内联的(d)(对于速度来说,这是一件好事)。

Before the object file is created by the compiler the preprocessor is called (-E option for gcc) and the result is sent to the compiler which creates the object out of code.

在编译器创建对象文件之前,调用预处理器(gcc的-E选项),并将结果发送给编译器,编译器从代码中创建对象。

So the shorter answer is:

简短的回答是:

-- Declaring functions in header is good for speed (but not for space) --

——在header中声明函数有利于速度(而不是用于空间)。

#6


1  

You should use inline functions. Read this Inline Functions for a better understanding and the tradeoffs involved.

您应该使用内联函数。阅读这个内联函数,以便更好地理解和权衡。

#7


1  

C++ won’t complain if you do, but generally speaking, you shouldn’t.

如果您这样做了,c++就不会抱怨了,但是一般来说,您不应该抱怨。

when you #include a file, the entire content of the included file is inserted at the point of inclusion. This means that any definitions you put in your header get copied into every file that includes that header.

当您#include文件时,包含文件的整个内容将插入到包含点。这意味着,您在头文件中放入的任何定义都将被复制到包含头文件的每个文件中。

For small projects, this isn’t likely to be much of an issue. But for larger projects, this can make things take much longer to compile (as the same code gets recompiled each time it is encountered) and could significantly bloat the size of your executable. If you make a change to a definition in a code file, only that .cpp file needs to be recompiled. If you make a change to a definition in a header file, every code file that includes the header needs to be recompiled. One small change can cause you to have to recompile your entire project!

对于小型项目来说,这可能不是什么大问题。但是对于较大的项目来说,这可能会使编译工作花费更长的时间(因为每次遇到相同的代码时都会重新编译),并且可能会大大增加可执行文件的大小。如果对代码文件中的定义做了更改,则只需要重新编译.cpp文件。如果更改头文件中的定义,则需要重新编译包含头文件的每个代码文件。一个小小的改变就会导致你不得不重新编译你的整个项目!

Sometimes exceptions are made for trivial functions that are unlikely to change (e.g. where the function definition is one line).

有时,对于不太可能更改的琐碎函数(例如函数定义为一行),则会出现异常。

#1


62  

If the function is small (the chance you would change it often is low), and if the function can be put into the header without including myriads of other headers (because your function depends on them), it is perfectly valid to do so. If you declare them extern inline, then the compiler is required to give it the same address for every compilation unit:

如果函数很小(更改它的可能性很小),并且如果可以将函数放入header中,而不包含其他的header(因为您的函数依赖于它们),那么这样做是完全有效的。如果您以内联方式声明它们,则要求编译器为每个编译单元提供相同的地址:

headera.h:

headera.h:

inline string method() {
    return something;
}

Member functions are implicit inline provided they are defined inside their class. The same stuff is true for them true: If they can be put into the header without hassle, you can indeed do so.

成员函数是隐式内联的,只要它们是在类中定义的。同样的事情对他们来说也是正确的:如果他们可以毫不费力地放入标题,你确实可以这么做。

Because the code of the function is put into the header and visible, the compiler is able to inline calls to them, that is, putting code of the function directly at the call site (not so much because you put inline before it, but more because the compiler decides that way, though. Putting inline only is a hint to the compiler regarding that). That can result in a performance improvement, because the compiler now sees where arguments match variables local to the function, and where argument doesn't alias each other - and last but not least, function frame allocation isn't needed anymore.

因为函数的代码放到页眉和可见的,编译器可以内联调用它们,也就是说,把函数的代码直接调用站点(不是因为你把内联之前,但更多的,因为编译器决定,。只放置内联是对编译器的一个提示)。这可以提高性能,因为编译器现在看到参数与函数本地变量匹配的地方,以及参数之间不存在别名的地方——最后但同样重要的是,不再需要函数框架分配。

My understanding is when the compilation is done, compiler will expand the header file and place it where it is included. Is that correct?

我的理解是编译完成后,编译器将展开头文件并将其放置在包含它的地方。那是正确的吗?

Yes, that is correct. The function will be defined in every place where you include its header. The compiler will care about putting only one instance of it into the resulting program, by eliminating the others.

是的,这是正确的。函数将在包含它的头的每个地方定义。编译器只关心将它的一个实例放入结果程序中,消除其他实例。

#2


12  

Depending on your compiler and it's settings it may do any of the following:

取决于你的编译器和它的设置,它可以做以下任何一种:

  • It may ignore the inline keyword (it is just a hint to the compiler, not a command) and generate stand-alone functions. It may do this if your functions exceed a compiler-dependent complexity threshold. e.g. too many nested loops.
  • 它可以忽略inline关键字(它只是对编译器的提示,而不是命令),并生成独立函数。如果您的函数超过了依赖于编译器的复杂性阈值,那么可以这样做。太多的嵌套循环。
  • It may decide than your stand-alone function is a good candidate for inline expansion.
  • 它可能会决定您的独立函数是否适合内联扩展。

In many cases, the compiler is in a much better position to determine if a function should be inlined than you are, so there is no point in second-guessing it. I like to use implicit inlining when a class has many small functions only because it's convenient to have the implementation right there in the class. This doesn't work so well for larger functions.

在许多情况下,编译器可以更好地确定一个函数是否应该内联,因此没有必要对它进行事后批评。当一个类有许多小函数时,我喜欢使用隐式内联,因为在类中有实现是很方便的。对于更大的函数来说,这不是很好。

The other thing to keep in mind is that if you are exporting a class in a DLL/shared library (not a good idea IMHO, but people do it anyway) you need to be really careful with inline functions. If the compiler that built the DLL decides a function should be inlined you have a couple of potential problems:

另一件需要记住的事情是,如果在DLL/共享库中导出一个类(不是个好主意,但人们还是会这么做),那么您需要对内联函数非常小心。如果构建DLL的编译器认为一个函数应该内联,那么您就会遇到一些潜在的问题:

  1. The compiler building the program using the DLL might decide to not inline the function so it will generate a symbol reference to a function that doesn't exist and the DLL will not load.
  2. 使用DLL构建程序的编译器可能决定不内联该函数,因此它将生成一个对不存在的函数的符号引用,并且DLL将不会加载。
  3. If you update the DLL and change the inlined function, the client program will still be using the old version of that function since the function got inlined into the client code.
  4. 如果您更新DLL并更改内联函数,客户端程序将仍然使用该函数的旧版本,因为该函数已内联到客户端代码中。

#3


4  

There will be an increase in performance because implementation in header files are implicitly inlined. As you mentioned your functions are small, inline operation will be so beneficial for you IMHO.

由于头文件中的实现是隐式内联的,因此性能会有所提高。正如您提到的,您的函数很小,内联操作对您非常有益。

What you say about compiler is also true.There is no difference for compiler—other than inlining—between code in header file or .cpp file.

你说的编译器也是正确的。除了在头文件或.cpp文件中的代码之间进行内联之外,编译器没有任何区别。

#4


2  

  1. If your functions are that simple, make them inline, and you'll have to stick them in the header file anyway. Other than that, any conventions are just that - conventions.

    如果您的函数非常简单,请将它们内联,并且您将不得不将它们放在头文件中。除此之外,任何约定都只是那个约定。

  2. Yes, the compiler does expand the header file where it encounters the #include statements.

    是的,编译器确实扩展了遇到#include语句的头文件。

#5


1  

It depends on the coding standards that apply in your case but:

这取决于适用于您的情况的编码标准,但是:

Small functions without loops and anything else should be inlined for better performance (but slightly larger code - important for some constrained or embedded applications).

没有循环和其他任何东西的小函数应该内联以获得更好的性能(但是稍微大一点的代码——对于某些受限或嵌入式应用程序很重要)。

If you have the body of the function in the header you will have it by default inline(d) (which is a good thing when it comes to speed).

如果在header中有函数的主体,那么默认情况下它是内联的(d)(对于速度来说,这是一件好事)。

Before the object file is created by the compiler the preprocessor is called (-E option for gcc) and the result is sent to the compiler which creates the object out of code.

在编译器创建对象文件之前,调用预处理器(gcc的-E选项),并将结果发送给编译器,编译器从代码中创建对象。

So the shorter answer is:

简短的回答是:

-- Declaring functions in header is good for speed (but not for space) --

——在header中声明函数有利于速度(而不是用于空间)。

#6


1  

You should use inline functions. Read this Inline Functions for a better understanding and the tradeoffs involved.

您应该使用内联函数。阅读这个内联函数,以便更好地理解和权衡。

#7


1  

C++ won’t complain if you do, but generally speaking, you shouldn’t.

如果您这样做了,c++就不会抱怨了,但是一般来说,您不应该抱怨。

when you #include a file, the entire content of the included file is inserted at the point of inclusion. This means that any definitions you put in your header get copied into every file that includes that header.

当您#include文件时,包含文件的整个内容将插入到包含点。这意味着,您在头文件中放入的任何定义都将被复制到包含头文件的每个文件中。

For small projects, this isn’t likely to be much of an issue. But for larger projects, this can make things take much longer to compile (as the same code gets recompiled each time it is encountered) and could significantly bloat the size of your executable. If you make a change to a definition in a code file, only that .cpp file needs to be recompiled. If you make a change to a definition in a header file, every code file that includes the header needs to be recompiled. One small change can cause you to have to recompile your entire project!

对于小型项目来说,这可能不是什么大问题。但是对于较大的项目来说,这可能会使编译工作花费更长的时间(因为每次遇到相同的代码时都会重新编译),并且可能会大大增加可执行文件的大小。如果对代码文件中的定义做了更改,则只需要重新编译.cpp文件。如果更改头文件中的定义,则需要重新编译包含头文件的每个代码文件。一个小小的改变就会导致你不得不重新编译你的整个项目!

Sometimes exceptions are made for trivial functions that are unlikely to change (e.g. where the function definition is one line).

有时,对于不太可能更改的琐碎函数(例如函数定义为一行),则会出现异常。