c ++模板会使程序变慢吗?

36 c++ performance templates

我从许多人那里听说过使用模板会使代码变慢.这是真的吗?我正在建立一个图书馆.有些地方如果没有创建模板,就会导致代码管理问题.截至目前,我可以想到两个解决这个问题的方法:

  • 使用#defines

  • 使用模板并在头文件/库本身中定义所有可能的类型,但不允许最终用户创建模板实例.

例如typedef Graph<int> GraphI32;

无论如何,是否限制用户自己创建各种模板实例.

对上述查询的帮助将受到高度重视.

Jer*_*fin 57

最简洁的答案是不.如需更长的答案,请继续阅读.

正如其他人已经指出的那样,模板没有直接的运行时惩罚 - 即他们的所有技巧都发生在编译时.然而,间接地,它们可以在一些情况下减慢速度.特别是,模板的每个实例化(通常)都会产生与其他实例化分离且唯一的代码.在少数情况下,这可能导致执行缓慢,只需生成足够的目标代码,使其不再适合缓存.

编辑:澄清关于代码大小的情况:是的,大多数编译器可以并且将相同实例化的代码折叠在一起- 通常情况下,实例化的实例完全相同.编译器不会插入代码来执行最简单的转换以获得适合现有实例的用法.例如,正常的函数调用可以/将转换T *T const *使用任何一个const或非const参数的调用将使用相同的代码(除非你选择在constness 上重载函数,在这种情况下你可能已经专门这样做了为这两种情况提供不同的行为).使用模板,这不会发生-在实例T *T const *会导致两个正在生成的代码完全独立的部分.这是可能的编译器(或链接)也许能够将二者合并后的事实,但不能完全肯定(例如,我当然使用的编译器没有).

模板对速度的积极影响远远超过负面.

  • 缓存exaustion与模板无关.如果编译器必须生成大量代码,那么你必须也必须手动生成代码(没有模板),存在相同的情况.所以这是一个完全红鲱鱼. (6认同)
  • 实际上,每个现代编译器都能够在不同的模板实例中将公共代码折叠在一起 - 实际上,通常将常见的生成代码折叠在一起,即使对于看似无关的代码段也是如此.这是一个非常基本的优化.编译器是链接器比你聪明. (5认同)
  • @Terry,Steve,Martin:编译器无法执行优化,因为每个实例化的函数都必须具有唯一的地址,以便函数指针比较起作用.vector <int> :: push_back和vector <unsigned int> :: push_back将始终具有不同的地址,因此它们永远不会共享相同的二进制代码.这与始终生成内联函数的非内联版本的原因相同.一个聪明的整个程序优化编译器可以跟踪地址是否从未被模板化函数和*然后*允许它们合并,但我不知道是否有任何编译器实际上这样做. (3认同)
  • @Terry:一个虚拟程序,它生成 std​​::vector&lt;int&gt; 和 std::vector&lt;unsigned int&gt; 并将一个数字推到它们两个上,然后打印它们,在生成的可执行文件上运行“nm”,即使进行了优化,显示两者的符号(与许多调试模式相比,只有 1 个冗余符号,但我认为这是因为内联,而不是您描述的优化)。(使用 GCC 4.2 和 -O2) (2认同)

sep*_*p2k 20

由于模板实例化在编译时发生,因此使用模板没有运行时成本(事实上模板有时用于在编译时执行某些计算以使程序运行得更快).然而,大量使用模板会导致编译时间过长.

  • 大多数情况下,但由于模板函数的多次实例化而增加的代码大小会增加指令缓存未命中率,并减慢程序速度.在某些情况下,非模板函数可以真正为多种类型(例如int,short和long)提供服务,并且使用较少的可执行代码. (5认同)
  • @John:编译器只对实际使用的类进行实例化.如果使用非模板化代码,则存在相同的情况,因为开发人员必须手动生成所有类.所以这虽然技术上真实,但与模板无关,这将是一个设计问题,并且使用或不使用天气模板. (2认同)
  • @Martin York:例如,我想对一个 int 数组、一个 float 数组和一个 double 数组进行排序。我可以调用“std::sort”的三个不同实例,或者可以调用“qsort”三次。可以想象后者会产生更小的代码吗?您当然可以争辩说,程序员*可能*会在不使用模板的情况下增加多个几乎相同的函数,但实际上他们通常不会这样做,哪怕只是因为打字会很可怕。 (2认同)
  • 您说,“如果使用非模板化代码,则会存在相同的情况,因为开发人员必须手动生成所有类”。我的观点是,这是一个稻草人。通常,如果使用非模板化代码,开发人员不会手动生成所有类,并且不会存在相同的情况。事实上,开发人员会找到其他一些方法来编写通用代码,正是针对这种方法,对使用模板是否是一个好主意进行了理智的分析。当然这是一个好主意,只是不是因为如果你不使用它,你就一定会 c'n'p。 (2认同)
  • 作为比较:问:“使用 Java 开发应用程序会比使用汇编程序更快吗?”。答:“不。如果你用 Java 编写它,就像在 asm 中一样,你只会有一个代表内存映射的大量整数数组,并且你将使用该数组的索引来执行加法、乘法等操作汇编代码中的指针。这并不容易。当然,您*可能*决定在 Java 中使用变量、对象和 GC。这可能会加快开发速度,但这是一种故意的权衡和设计决定,与Java无关”或A.“可能”?;-) (2认同)
  • 类似地,如果您将相同的任务分配给同一个程序员,非模板代码将(我怀疑,尽管我可能是错的:那是另一个线程)比模板代码小一些,内联更少。如果模板可以很好地处理这项任务,那么非模板代码的执行速度可能也会较慢。错误(如果提问者的线人甚至沿着这些思路思考)是认为较大的模板代码会更慢。据我所知,认为它会更大并不是一个错误。当然,无论哪种方式,我们都可以举出可信的例子。 (2认同)

小智 14

不,他们没有.当你发现你已经"听到"某些东西而无法命名来源时,你几乎可以肯定地保证你所听到的是错误的.事实上,模板往往会加快代码速度.

阅读有关该主题的权威书籍,而不是依赖于听力,我推荐使用C++模板 - 完整指南.


fab*_*ioM 7

模板使编译变慢.但大多数时候它使程序更快.


duf*_*ymo 6

它们确实使目标代码更大,因为C++为您使用的每种类型生成代码.但我不相信这会降低执行速度.我没有数字可以暗示它会.

在代码开发,阅读和维护过程中,它确实可以改善您的生活.我不会让编码都市神话阻止你使用一个明显有用的语言功能.

  • 足够避免使用它们?我拒绝. (6认同)