C / C ++中未使用的包含有害内容吗?


74

未使用的容器的负面影响是什么?

我知道它们会导致二进制文件大小增加(或者是?),还有其他吗?


5
对于修剪包括“ Header Hero”
2011年

4
附带问题:有人知道有什么工具可以自动删除未使用的包含吗?
乔治

Answers:


85
  • 增加编译时间(潜在的严重问题)
  • 污染全局名称空间。
  • 预处理程序名称的潜在冲突。
  • 如果第三方库中包含未使用的头,则可能会使此类库不必要地维护为依赖项。

1
潜在的严重问题?我也相信这一点,但是当我发布关于此的问题时,我一直被嘲笑。某种程度上,似乎不必要的包含似乎不是一个严重的问题,这已被广泛接受。
乔治

我认为可能很严重,因为对于某些人来说,不一定是很严重的问题。取决于个人或项目团队的偏好和优先级。
mloskot 2011年

我从以下意义上解释了您的答案:未使用的include可以明显增加编译时间。因此,这可能会成为一个问题,您必须小心。通过良好的纪律,您可以避免或减少未使用的包含项。
乔治

Giorgio,是的,这就是潜力(“它可能会成为问题”)。
mloskot 2011年

1
具体来说,我认为当有成百上千个不必要的头文件时,这个问题在大型项目上会变得越来越严重。在此答案中谈论诸如卫兵或预编译头文件之类的内容可能不会有任何伤害。
mwd


21

主要问题是混乱。这些是杂波显现的三个主要方面:

  1. 视觉污染;而当您试图找出您确实需要的其他物品时。

  2. 逻辑污染;它更有可能发生功能冲突,需要更多的时间进行编译(对于几个include来说可能确实很小,但是如果它成为不清理不需要的include的“策略”,则可能会成为一大障碍)。

  3. 依赖不透明;由于要分析的标头更多,因此很难确定代码中的依赖关系周期。当您的代码库增长到业余爱好者级别以外的任何重要级别时,了解代码中的依赖项至关重要。


16

一般来说,是的,确实会引起一些问题。从逻辑上讲,如果您不需要它,则不要包含它。

  • 在标头中声明为外部并在源文件中定义的任何单例将包含在您的程序中。这显然会增加内存使用量,并可能导致更频繁地访问其页面文件,从而可能导致性能开销(现在已经不是什么大问题,因为单例的大小通常为中小型,因为我认识的大多数人都有6+ GB RAM)。

  • 编译时间会增加,并且对于经常编译的大型商业项目而言,这可能会导致资金损失。它可能只增加总时间几秒钟,但是将其乘以数百次编译,则可能需要测试和调试,并且浪费了大量时间,因此转换为利润损失。

  • 标头越多,与您在程序或其他标头中定义的宏发生预料之外的冲突的可能性就越大。可以通过正确使用名称空间来避免这种情况,但这仍然很麻烦。再次,损失了利润。

  • 导致代码膨胀(文件更长,因此读取更多),并且可以在很大程度上增加您在IDE的自动完成工具中找到的结果的数量(有些人虔诚反对这些工具,但是它们确实在一定程度上提高了生产率)。

  • 您可能不知不觉地将其他外部库链接到程序中。

  • 这样做可能会无意间导致世界末日。


8

我假设标头都可以被认为是“真诚的”,也就是说,它们不是为了破坏您的代码而精确编写的。

  • 通常会减慢编译速度(预编译的标头会减轻这一点)

  • 这意味着没有真正存在的依赖项(这是语义错误,而不是实际错误)

  • 宏会污染您的代码(通过在BOOST_FOREACH而不是FOREACH中使用带有类似名称空间的名称的宏前缀来缓解)

  • 标头可能暗示指向另一个库的链接。在某些情况下,未使用的标头可能会要求链接程序将您的代码与外部库链接(请参阅MSCV的#pragma comment(lib,“”))。我相信,如果不使用一个好的链接程序,它将不会保留该库的引用(IIRC,MSVC的链接程序将不会保留未使用的库的引用)。

  • 删除标头可以减少意外错误。如果您不信任标头(某些编码器要好于其他编码器...),则删除标头可以消除风险(您不希望包含标头来更改所有内容的结构对齐方式:生成的错误是.. 。照亮...)。

  • 标头的static变量声明将污染您的代码。每个静态变量声明将导致在已编译源中声明一个全局变量。

  • C符号名称会污染您的代码。标头中的声明将污染您的全局或结构名称空间(并且很可能会同时污染这两者,因为结构通常是类型定义的,以将其类型引入全局名称空间)。库为它们的符号加上某种“名称空间名称”(例如SDL_CreateMutexSDL)可以减轻这种情况。

  • 非命名空间的C ++符号名称会污染您的代码。由于上述相同原因。对于错误使用该using namespace语句的标头也是如此。现在,正确的C ++代码将为其符号命名空间。是的,这意味着您通常不应该信任在全局命名空间中声明其符号的C ++头...


6

它们是否增加二进制大小实际上取决于它们中的内容。

主要的副作用可能是对编译速度的负面影响。同样,影响的大小取决于其中的内容,数量以及它们是否包含其他标题。


2

好吧,让他们离开那里只会延长编译时间,并增加了不必要的编译依赖性。


2

它们代表笨拙的设计。

如果您不确定要包括什么和不包括什么,则表明开发人员不知道自己在做什么。

包含文件仅在需要时才包括在内。如今,随着计算机内存和速度的飞速增长,这可能不是很多问题,但也许曾经是。

如果不需要包含但无论如何都包含,我建议在它旁边添加一个注释,说明为什么包含它。如果新开发人员继续使用您的代码,那么如果您以正确的方式进行操作,他将对您非常感谢。


0

include表示您要添加更多声明。因此,在编写自己的全局函数时,需要谨慎考虑该函数已包含在标头中。

例如 如果您编写自己的类auto_ptr {}而不包含“内存”,它将很好地工作。但是只要您包含内存,编译器就会给出错误,因为它已经在内存头文件中声明了


不,不会,因为<memory>它将声明一个std :: auto_ptr。这是C ++中名称空间的重点。一个纯C的例子将是一个更好的例子……
paercebal 2011年

1
you are redefining class auto_ptr so it will give error:你不明白。<memory>auto_ptr受名称空间保护std,因此您可以auto_ptr在全局名称空间中编写自己的类,甚至可以在自己的名称空间中编写更好的类,并且不会与之冲突,std::auto_ptr因为您受到C ++名称空间的保护,这使两个类完全不同。因此,没有编译错误。
paercebal

0

是的,由于外部未使用的变量,它们可以增加二进制大小。

//---- in unused includes ----
extern int /* or a big class */ unused_var;

//---- in third party library ----
int unused_var = 13;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.