我正在处理一小段C / C ++源代码。程序从stdin读取输入值,用算法处理它们并将结果写入stdout。
我只是在单个文件中实现所有这些,但我也想要算法的测试用例(而不是输入/输出读取),所以我的项目中有以下文件:
我马上在sort.hpp中实现算法,没有sort.cpp。它相当短,没有任何依赖。
你是否会说,在某些情况下,标题中定义的函数是可以的,即使它们是复杂的算法而不仅仅是简单的访问器/ mutator?或者我有理由避免这种情况吗?我应该何时将代码从头文件移动到源文件?
答案 0 :(得分:8)
只要您了解权衡,在头文件中使用函数没有任何问题。将它们放在头文件中意味着它们必须在包含头的任何转换单元中编译(和重新编译)。 (并且必须将它们声明为inline
,否则您将收到链接器错误。)
在包含许多翻译单元的项目中,如果你做了很多,这可能会导致编译时间明显减慢。
另一方面,它确保函数定义在调用函数的任何地方都可见 - 这意味着它可以简单地内联,因此生成的程序可以运行得更快。
最后,使用功能模板,您通常没有现实的选择。定义必须在呼叫站点上可见,唯一可行的方法是将其放在标题中。
最后一个考虑因素是仅标头库更易于部署和使用。你不需要链接任何东西,你不必担心ABI或其他任何东西。您只需将标题添加到项目中,包括它们即可。
相当多的流行图书馆使用仅限标题的策略。
答案 1 :(得分:1)
只要它是inline
,就可以在标题中添加任何函数。 class { }
和模板中定义的函数等内容隐式inline
。
如果生成的应用程序变得太大,则优化代码大小。在出现问题之前进行优化是一种反模式,特别是当“按照自己的方式”执行操作时有一个好处,并且修复就像从一个文件移动到另一个文件并删除inline
一样简单。
当然,如果要将代码作为库分发,则在标题,静态库或动态库二进制文件之间进行决策是影响用户的重要决策。
答案 2 :(得分:1)
当您将函数放入标题时,您必须确保声明它们inline
。当多个.cpp文件包含该头文件时,这是避免重复定义警告所必需的。通常,您应该只在头文件中放置小函数,因为它将针对包含标头的每个cpp文件进行编译,这将减慢编译时间并导致代码膨胀;更大的可执行文件。
答案 3 :(得分:0)
这真是一个阶梯选择。但是将它放在标题中意味着它将是内联代码而不是函数。如果您想要相同的功能,可以使用inline关键字:
inline int max(int a, int b)
{
return (a > b) ? a : b;
}
答案 4 :(得分:0)
您应该避免这种情况(对于非内联函数)是因为多个源文件将包含您的标头,从而产生链接器错误。 如果你有一个pramga曾经或类似的技巧并不重要 - 如果你有多个包含相同标题的编译单元(例如cpp文件),则会出现重复。
答案 5 :(得分:0)
绝大多数boost库只是标题库,所以我会说:是的,这是一种既定且公认的做法。只是不要忘记inline
。
答案 6 :(得分:0)
如果你想内联函数,它必须在标题中,否则它不能内联。
如果您使用库发布标题并且标题中包含某种实现,那么您可以确定几年之后如果更改实现并且它的工作方式与以前完全不同一些人的代码将破裂,因为他们将依赖于他们在标题中看到的实现。是的,我知道不应该这样做,但很多人确实在标题中查找实现以及他们可以以无意的方式利用/使用的其他行为来克服他们遇到的一些问题。
如果您打算使用模板,那么您别无选择,只能将其全部放入标题中。 (如果您的编译器支持导出模板但是我只知道1个,则可能没有必要这样做。)
答案 7 :(得分:0)
可以在标题中实现。这取决于你需要什么。如果将定义分离到另一个文件,则编译器将创建具有外部链接的符号,如果您不希望可以在头文件本身内定义函数。但是你会浪费一些代码段的内存。如果将此头文件包含在两个不同的文件中,则两个文件代码段都将具有此函数定义。
如果其他头文件将具有类似名称的函数,那么它将成为一个问题。然后你必须使用内联。