2015-11-03 93 views
3

当某些C++实体(如结构,类或函数)被声明为模板时,为所述实体提供的定义仅为必须实例化的蓝色打印。C++模板:模板实例是内联的吗?性能有缺点吗?

由于模板实体必须在声明时定义(通常是头文件),所以我有这个概念,我试图说服自己是错的,当模板实例化后,它会由编译器内联。我想问问这是否是这样?

question的答案引起了我的怀疑,当我读到的段落:

“模板可导致慢编译时间和可能更大 可执行文件,尤其是年纪较大的编译器。”

由于模板必须实例化,但为什么“可能更大的可执行文件”更慢,编译时间更慢?这应该以什么方式解释?我应该把它解释为'许多函数是内联的',或者'如果有很多模板实例化,可执行文件的大小就会增加,这就是同一个模板被很多不同的类型实例化,这会导致同一个实体的多个副本出现' ?

在后一种情况下,较大的可执行文件大小是否会导致软件运行速度较慢,因为需要将更多代码加载到内存中,这会导致代价很高的分页?

此外,由于这些问题也有些依赖于编译器,所以我对Visual C++编译器感兴趣。关于大多数编译器所做的一般性回答也提供了良好的洞察力。

预先感谢您。

+5

您可以拥有更多代码的一个原因是每个模板类型都是它自己的类型。所以你所有的'Foo '的代码必须重复'Foo ' – NathanOliver

+0

@NathanOliver好吧,正如我现在所了解的,最新的链接器实现(g ++ 5.x)能够合并相同的生成的实例化代码。 –

+1

@πάνταῥεῖ你能提供一个链接吗?这听起来很有趣。 – bolov

回答

3

由于,当它被宣布为模板实体必须定义的事实(这通常是头文件)

事实并非如此。您可以分别声明和定义模板类,方法和函数,就像您可以使用其他类,方法和函数一样。

我有一个概念,我试图说服自己是错的,当模板被实例化后,它会被编译器内联。我想问问这是否是这样?

其中一些可能是或全部或不是全部。编译器会做它认为最好的。

由于模板必须实例化,为什么“可能更大的可执行文件”更慢,编译时间更慢?这应该以什么方式解释?

它可以用多种方式解释。以同样的方式,一瓶阿斯匹林含有警告“可能会导致<插入副作用在这里>”。

我应该解释为“很多内联函数”或“可执行文件的大小增加时,如果有许多模板实例,即同一模板实例有很多不同的类型,这将导致的多个副本相同的实体在那里'?

您将不会有同一个实体的多个副本 - 编译器套件有责任看到这一点。即使方法是内联,该方法的实际地址:

  1. 始终存在,并
  2. 时由多个编译单元中引用相同的地址。

您可能发现的是,您开始创建比预期更多的类型。例如std::vector<int>是与std::vector<double>完全不同的类型。 foo<X>()是与foo<Y>()不同的功能。程序中的类型和函数定义的数量可以快速增长。

在后一种情况下,较大的可执行文件大小是否会导致软件运行速度较慢,因为必须将更多的代码加载到内存中才能导致代价较高的分页?

过度的寻呼,可能不是。过度的缓存未命中,很可能。通常情况下,优化较小的代码是实现良好性能的一个很好的策略(在某些情况下,例如,当数据很少被访问,并且全部在高速缓存中时)。

+1

值得一提的是,_inlining_仅仅是编译器在链接阶段所做的决定。 –

+0

我认为你会混淆内联(编译器决定)和合并COMDAT(链接器责任) –

0

它们是否内联总是由编译器决定。非内联模板实例化为所有类似实例共享。

所以很多翻译单元都希望做一个Foo<int>将共享Foo实例化。显然,如果Foo<int>是一个函数,并且编译器决定在每种情况下内联它,那么代码将重复。但是内联的选择是因为这样做的优化看起来很可能优于函数调用。

从技术上讲,可能是是模板导致执行速度较慢的一种情况。我使用的软件具有超紧密的内部循环,因此我们进行了大量的性能测量。我们使用了许多模板函数和类,与手动编写代码相比,它还没有显示出降级。

我不能肯定,但我认为你必须有在模板的情况: - 产生的非联的代码 - 这样做的多个实例 - 本来是一个手写功能 - 手写函数不会导致运行时间受到一个函数的惩罚(即:没有隐式转换涉及运行时检查)

然后有可能您有一种情况,即单手写函数适合CPU的指令缓存但多个模板实例化没有。

+0

当我几年前测试,因为不良引起的内联选择严重的性能问题ICC,GCC和MSVC,个个有这些问题,所有这些问题都是直接由于内联的自顶向下的设计。由于内联而导致性能灾难的具体情况各不相同,但都有。首先内嵌一个不应该内联的大模板函数。将内容嵌入到内容中,然后失败(由于自上而下的限制),以便内嵌真正需要内联的内容。 – JSF

+0

@JSF够公平的。我无法说出你的经历。我们在基于CPU的渲染器上工作,所以任何缓存缺失都会大幅降低性能。然而,我们并不倾向于制作大型功能模板,也不会嵌套太深的层次。我们的问题(奇怪)并不是它在内联时内联,而是内联失效。在这方面,MSVC似乎早于其他编译器放弃。 – qeadz