假设我有以下模板类,其中包含一个静态成员函数,该函数本身实例化一个静态变量(在第一次调用其包含例程时,它实际上是一个静态成员变量):
template <typename T>
struct foo
{
static int& mystatic()
{
static int value;
return value;
}
};
如果我在一些foo<T>
的多个翻译单元中使用T
,编译器会将foo<T>::mystatic::value
放入哪个目标文件中?如何在链接时解决这种明显的重复/冲突?
答案 0 :(得分:1)
您是否明白您的函数mystatic
是一个具有外部链接的函数?这意味着在不同翻译单元中制作的mystatic
的多个定义之间存在完全相同的冲突。此外,没有模板可能会出现完全相同的问题:在头文件中定义的具有外部链接的普通inline
函数可以产生相同的明显多重定义冲突(同样可以在那里再现局部静态变量的问题)
为了解决这些冲突,编译器以某种依赖于实现的方式标记所有这些符号。通过这样做,编译器向链接器传达这样的事实:这些符号可以合法地最终定义多次。例如,一种已知的实现将这些符号放入目标文件的单独部分(有时称为“COMDAT”部分)。其他实现可能以某种其他方式标记这些符号。当链接器在多个目标文件中发现此类符号时,它不会报告多重定义错误,而是选择每个相同符号的一个,并在整个程序中使用它。链接器将丢弃每个此类符号的其他副本。
这种方法的一个典型结果是,您的本地静态变量value
必须作为外部符号包含在每个目标文件中,尽管它从语言的角度来看没有链接。符号的名称通常由函数名mystatic
和变量名value
以及其他一些错误组成。
换句话说,编译器正确地将mystatic
和变量value
的定义放入使用成员函数的所有独立目标文件中。链接器稍后将确保链接程序中只存在一个mystatic
和仅一个value
。可能无法确定哪个原始目标文件提供了幸存的副本(如果这种区别甚至有意义的话)。