1
12
您提出的问题是错误的——您示例中的任何“膨胀”都与模板无关。(你的问题的答案是,顺便说一句,取两个模块中成员函数的地址,你会发现它们是相同的) 您真正想问的是,对于每个模板实例化,生成的可执行文件是否线性增长?答案是否定的,链接器/优化器会变魔术。 编译创建一个类型的exe:
注意生成的exe大小。现在再做一次:
等等,对于大约30个不同的版本,用图表标出生成的exe大小。如果模板像人们想象的那样糟糕,那么每个唯一的模板实例化的exe大小将增加一个固定的量。 |
2
10
在这种特定的情况下,如果您对访问器进行了任何优化,您会发现g++将倾向于内联访问器。尽管调用的开销是否会减少还是有争议的。
但是,验证编译内容的一个简单方法是使用
你会看到
如果
|
3
7
模板与此无关。 考虑一下这个小程序: A.H:
B.CPP:
CCPP:
没有模板,但有完全相同的问题。相同的函数在多个翻译单元中定义。规则是相同的:在最终程序中只允许存在一个定义,否则编译器将无法确定要调用哪个定义,否则指向同一函数的两个函数指针可能指向不同的地址。 模板代码膨胀的“问题”是不同的:如果你为同一个模板创建了很多不同的实例化。例如,使用您的类,这个程序将冒代码膨胀的风险:
严格来说,编译器需要创建
模板没有魔力。他们不会神秘地“膨胀”你的代码。他们只是给你一个工具,让你很容易创建一个巴吉利昂不同类型从同一个模板。如果您实际使用所有这些类型,它必须为所有类型生成代码。和C++一样,你为你所用的东西付费。如果您同时使用
|
4
4
更好地说明 代码膨胀 使用模板是使用模板来生成代码,而不是变量。典型的恐慌是由于编译器为模板(模具)的每个实例生成代码。这类似于由于内联函数和方法而导致的代码膨胀。然而,现代编译器和链接器可以执行magick来减小代码大小,这取决于优化设置。 例如:
上面的代码最好被认为是一个模板。编译器将根据传递给的类型生成代码
担心的是编译器将使用相同的变量类型为每个实例化生成代码,从而构建重复的代码:
当模板(模具)在不同的翻译单元中实例化时,恐惧也可以扩展。 现代的编译器和链接器很聪明。智能编译器可以识别模板函数调用,并将其转换为一些唯一的损坏名称。编译器将只对每个调用使用一个实例化。类似于函数重载。 即使编译器是草率的,并且生成了函数的多个实例(对于同一类型),链接器也会识别重复的实例,并且只将一个实例放入可执行文件中。 当使用失败时,函数或方法模板可以添加额外的代码。示例是大型函数,它们仅在一些区域中因类型而异。它们的非类型代码与依赖类型的代码比率很高。 上面例子的一个实现,具有较少的膨胀:
主要的区别在于,不依赖变量类型的代码已经分解为一个新函数。对于这个小例子来说,这似乎不值得,但它说明了这个概念。这个概念是将函数重构成依赖于变量类型和不依赖于变量类型的片段。依赖项被转换为模板化函数。 |
5
3
一个测试是在data()中放置一个静态变量,并在每次调用时增加它,并报告它。 如果myarray::data()占用了相同的代码空间,那么应该看到它先报告1,然后报告2。 如果没有,您应该只看到1。 我运行它,得到了1,然后是2,表明它是从同一组代码运行的。为了验证这是真的,我创建了另一个大小参数为50的数组,它将1踢出。 完整代码(有一些调整和修复)如下: Array.hpp:
类型:
X.CPP:
Y.CPP:
MCP.CPP:
|
6
3
下面是一个小实用程序脚本,我一直使用它来深入了解这些问题。它不仅显示了一个符号被定义了多次,而且还显示了每个符号占用的代码大小。我发现这对于审计代码大小问题非常有价值。 例如,下面是一个示例调用:
在本例中,我在单个.o文件上运行它,但您也可以在.a文件或可执行文件上运行它。在这里,我可以看到构造函数和析构函数被发出了两到三次,这是 this bug . 下面是脚本:
如果你自己运行这个.a文件或可执行文件,你应该能够让自己确信你确切地知道你的代码大小发生了什么。我相信最新版本的gcc可能会在链接时删除多余或无用的模板实例化,所以我建议您分析实际的可执行文件。 |
7
-1
生成的代码将完全相同,因为两个文件中的代码完全相同。如果需要,可以反汇编代码来检查它。 |
rookie · 检查函数模板的所有参数包参数是否属于int 1 年前 |
ivaigult · -W转换和隐式字符串到布尔类型转换 1 年前 |
rainer · 后台插入程序的初始化 1 年前 |
Community wiki · 以理智、安全和高效的方式复制文件 1 年前 |
Shefali Kanaujia · 对C中向量的向量进行排序++ 1 年前 |
Ma Joonyoung · 粗粒度和细粒度链表的时间比较 1 年前 |