假设我有两个.cpp文件,file1.cpp和file2.cpp,它们使用std::vector<int>
。假设file1.cpp有一个int main(void)
。如果我将两者编译成file1.o和file2.o,并将两个目标文件链接到我可以执行的elf二进制文件中。我正在使用32位Ubuntu Linux机器进行编译。
我的问题是关于编译器和链接器如何将std :: vector的符号组合在一起:
std::vector
的代码的代码以及包含f2.o的代码的另一组std::vector
代码?我为自己尝试了这个(我使用g++ -g
)并查看了我的最终可执行文件反汇编,我发现为矢量构造函数和其他方法生成的标签显然是随机的,尽管来自f1.o的代码似乎与f2.o中的代码调用了相同的构造函数。然而,我无法确定。
如果链接器确实阻止了代码重复,它是如何做到的?必须&#34;知道&#34;什么模板?是否总是会阻止关于跨多个目标文件多次使用相同模板化代码的代码重复?
答案 0 :(得分:9)
它通过name mangling了解模板的内容。对象的类型由编译器在其名称中编码,并允许链接器过滤掉同一模板的重复实现。
这是在链接期间完成的,而不是编译,因为每个.o文件都可以与任何东西链接,因此不能剥夺以后可能需要的东西。只有链接器可以决定哪些代码未使用,哪个模板是重复的等等。这是通过在对象的符号列表中使用“Weak Symbols”来完成的:如果链接器多次出现,链接器可以删除的符号(与其他符号,如用户定义的函数,如果重复则无法删除并导致链接错误。)
答案 1 :(得分:4)
您的问题在本文档的开头部分逐字说明:
http://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html
答案 2 :(得分:0)
从技术上讲,由于“一个定义规则”只有一个std::vector<int>
,因此代码应该链接在一起。可能会发生的一些代码是内联的,这会加快执行时间,但可能产生更多的代码。
如果您有一个文件使用std::vector<int>
而另一个文件使用std::vector<unsigned int>
,那么您将拥有2个类,并且可能会有大量重复的代码。
当然,向量的编写者可能会在某些情况下使用一些公共代码,例如POD类型,以消除重复。