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

发布于 2024-07-11 07:13:15 字数 330 浏览 6 评论 0原文

我有一堂课,有很多小功能。 我所说的小函数是指不进行任何处理而仅返回文字值的函数。 比如:

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

我创建了一个头文件“Foo.h”和源文件“Foo.cpp”。 但由于该函数非常小,我正在考虑将其放在头文件本身中。 我有以下问题:

  1. 如果我将这些函数定义放在头文件中,是否会出现性能或其他问题? 我会有很多这样的功能。
  2. 我的理解是,当编译完成后,编译器将扩​​展头文件并将其放置在包含它的位置。 那是对的吗?

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:

  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. My understanding is when the compilation is done, compiler will expand the header file and place it where it is included. Is that correct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

余罪 2024-07-18 07:13:15

如果函数很小(您经常更改它的机会很低),并且如果可以将函数放入标头中而不包含无数其他标头(因为您的函数依赖于它们),那么这样做是完全有效的。 如果将它们声明为外部内联,则编译器需要为每个编译单元提供相同的地址:

headera.h

inline string method() {
    return something;
}

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

因为函数的代码放在头文件中并且可见,所以编译器能够内联调用它们,即将函数的代码直接放在调用位置(不是因为你在它之前放置了内联,而是更多)因为编译器会这样决定,不过,仅内联是对编译器的一个提示)。 这可以提高性能,因为编译器现在可以看到参数在哪里与函数本地变量匹配,以及参数在哪里不互相别名 - 最后但并非最不重要的一点是,不再需要函数帧分配。

我的理解是,当编译完成后,编译器将扩​​展头文件并将其放置在包含它的位置。 这是正确的吗?

对,那是正确的。 该函数将在包含其标头的每个位置定义。 编译器将只关心将其一个实例放入生成的程序中,并消除其他实例。

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:

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.

坦然微笑 2024-07-18 07:13:15

根据您的编译器及其设置,它可能会执行以下任一操作:

  • 它可能会忽略 inline 关键字(它
    只是对编译器的提示,而不是
    命令)并生成独立的
    功能。 如果您的
    函数超出编译器依赖性
    复杂度阈值。 例如太多
    嵌套循环。
  • 它可能会决定你的独立
    函数是一个很好的候选函数
    内联扩展。

在许多情况下,编译器比您能够更好地确定函数是否应该内联,因此没有必要进行事后猜测。 当类有许多小函数时,我喜欢使用隐式内联,只是因为在类中实现它很方便。 这对于较大的函数来说效果不太好。

另一件要记住的事情是,如果您要在 DLL/共享库中导出类(恕我直言,这不是一个好主意,但人们无论如何都会这样做),您需要非常小心内联函数。 如果构建 DLL 的编译器决定应内联某个函数,则会出现一些潜在问题:

  1. 构建程序的编译器
    使用 DLL 可能会决定不
    内联函数,这样它就会
    生成对 a 的符号引用
    不存在的函数和
    DLL 将不会加载。
  2. 如果您更新 DLL 并更改
    内联函数,客户端程序
    仍将使用旧版本
    该函数自该函数以来
    内联到客户端代码中。

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.
  • 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:

  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. 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.
等风来 2024-07-18 07:13:15

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

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

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.

话少心凉 2024-07-18 07:13:15
  1. 如果您的函数那么简单,请将它们内联,无论如何您都必须将它们粘贴到头文件中。 除此之外,任何约定都只是约定。

  2. 是的,编译器会在遇到 #include 语句的地方扩展头文件。

  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.

紫轩蝶泪 2024-07-18 07:13:15

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

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

如果标头中有函数的主体,则默认情况下将具有 inline(d) (这对于速度而言是一件好事)。

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

所以简短的答案是:

-- 在标头中声明函数有利于速度(但不利于空间) --

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).

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.

So the shorter answer is:

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

岁月如刀 2024-07-18 07:13:15

如果你这样做,C++ 不会抱怨,但一般来说,你不应该抱怨。

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

对于小型项目,这可能不是什么大问题。 但对于较大的项目,这可能会使编译时间更长(因为每次遇到相同的代码时都会重新编译),并且可能会显着增大可执行文件的大小。 如果更改代码文件中的定义,则只需重新编译该 .cpp 文件。 如果更改头文件中的定义,则需要重新编译包含该头的每个代码文件。 一个小小的更改可能会导致您必须重新编译整个项目!

有时,对于不太可能更改的琐碎函数会出现例外情况(例如,函数定义只有一行)。

资料来源:http://archive.li/ACYlo(learcpp.com 上第 1.9 章的先前版本)

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

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.

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!

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

Source: http://archive.li/ACYlo (previous version of Chapter 1.9 on learncpp.com)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文