当一些C ++实体(例如结构,类或函数)被声明为模板时,为所述实体提供的定义只是必须实例化的蓝图。
由于模板实体在声明时必须定义(通常是头文件),我有一个概念,我试图说服自己是错误的,当模板被实例化后,它将是由编译器内联。我想问一下是不是这样?
当我阅读段落时,question的答案引起了我的怀疑:
“模板可能导致编译时间变慢,可能更大 可执行文件,特别是对于较旧的编译器。“
较慢的编译时间是明确的,因为模板必须实例化,但为什么“可能更大的可执行文件”?这应该以什么方式解释?如果有许多模板实例,我应该将其解释为“内联的许多函数”或“可执行文件的大小增加,即同一模板被实例化为许多不同类型,这会导致同一实体的多个副本存在” ?
在后一种情况下,更大的可执行文件大小会导致软件运行得更慢,因为必须将更多代码加载到内存中,这反过来会导致昂贵的分页吗?
另外,由于这些问题在某种程度上依赖于编译器,因此我对Visual C ++编译器感兴趣。关于大多数编译器确实提供了很好的见解的广义答案。
提前谢谢。
答案 0 :(得分:3)
由于模板实体在声明时必须定义(通常是头文件)
不正确。您可以单独声明和定义模板类,方法和函数,就像您可以使用其他类,方法和函数一样。
我有一个概念,我试图说服自己是错误的,当一个模板被实例化后,它将被编译器内联。我想问一下是不是这样?
其中一些可能是,或全部,或者都不是。编译器会做它认为最好的事情。
较慢的编译时间是明确的,因为模板必须实例化,但为什么“可能更大的可执行文件”?这应该以什么方式解释?
可以通过多种方式进行解释。就像一瓶Asprin包含警告“可能会导致<插入副作用>”一样。
我是否应将此解释为“内联的许多函数”或“如果存在许多模板实例,则可执行文件的大小会增加”,即同一模板将使用许多不同类型进行实例化,这会导致同一实体的多个副本在那里'?
您将不会拥有同一实体的多个副本 - 编译器套件有义务查看。即使方法是内联的,方法的地址也将是:
您可能会发现您开始创建的类型超出预期。例如,std::vector<int>
与std::vector<double>
完全不同。 foo<X>()
与foo<Y>()
的功能不同。程序中类型和函数定义的数量可以快速增长。
在后一种情况下,更大的可执行文件大小会导致软件运行得更慢,因为必须将更多代码加载到内存中,这反过来会导致昂贵的分页吗?
分页过多,可能不是。很可能是过多的缓存未命中。通常,优化较小的代码是实现良好性能的良好策略(在某些情况下,例如当访问的数据很少且全部都在缓存中时)。
答案 1 :(得分:0)
它们是否内联始终取决于编译器。所有类似实例都共享非内联模板实例化。
所以很多想要制作Foo<int>
的翻译单元都会分享Foo实例。显然,如果Foo<int>
是一个函数,并且编译器决定在每种情况下内联它,那么代码将重复。然而,内联的选择是因为这样做的优化似乎很可能优于函数调用。
从技术上讲,可能是一个角落,模板会导致执行速度变慢。我研究的软件具有超紧密的内环,我们可以对其进行大量的性能测量。我们使用了许多模板函数和类,与手工编写代码相比,它还没有出现降级。
我无法确定,但我认为您必须遇到模板的情况: - 生成的非内联代码 - 为多个实例化做了这样做 - 可能是一个手写功能 - 手写函数不会因为一个函数而导致运行时损失(即:没有涉及运行时检查的隐式转换)
然后,您可能会遇到单手写功能适合CPU指令缓存但多个模板实例不适合的情况。