内联变量跨边界唯一吗?

时间:2018-07-17 06:27:01

标签: c++ shared-libraries language-lawyer c++17 inline-variable

这是this question的后续行动。
如答案中的评论所述:

  

内联变量的属性-在每个翻译单元中都有相同的地址。 [...]通常,您是通过在cpp文件中定义变量来实现的,但是使用内联说明符,您只需在头文件中声明/定义变量,并且使用此内联变量的每个翻译单元都使用完全相同的对象。 / p>

此外,根据答案本身:

  

尽管该语言不能保证(甚至无法提及)跨共享库边界使用此新功能时会发生什么,但它确实可以在我的计算机上使用。

换句话说,不清楚当涉及共享库时,内联变量是否保证跨边界是唯一的。有人凭经验证明它可以在某些平台上工作,但这并不是正确的答案,它可能破坏其他平台上的一切。

在跨边界使用内联变量时,是否可以保证内联变量的唯一性?或者仅仅是我不应该依赖的实现细节?

3 个答案:

答案 0 :(得分:8)

这就是我解释标准的方式。根据{{​​3}}:

  

一个程序由一个或多个链接在一起的翻译单元组成。

它没有提到静态链接或动态链接。程序是链接在一起的翻译单元。链接是否分两个步骤完成(首先创建一个.dll / .so,然后动态的 linker 将所有动态libs +可执行文件链接在一起)无关紧要。

因此,按照我的解释,程序是动态链接还是静态链接都没有关系,实现的行为应相同:类静态变量应该是唯一的(无论是否为内联)。

在Linux上,这是真的。

在Windows上,这并非在所有情况下都有效,因此,按我的解释,它在这些情况下违反了标准(如果您创建一个单独的.dll,其中包含静态,非内联变量以及所有其他变量。 dll和exe引用了此变量,它可以正常工作。)

答案 1 :(得分:5)

C ++当前没有共享库的概念。因此,inline在共享库中的行为方式将取决于实现和平台。

[basic.link]/1指出“ 一个程序由一个或多个链接在一起的翻译单元组成。”这一事实并不意味着该程序与另一个已经链接的模块链接在一起。 ,其行为应相同。

多年来,为了纠正这种情况,已经提交了许多建议(N1400N1418N1496N1976N2407,{{ 3}},N3347),但都没有成功。用通用的方法很难实现,而C ++通常会尽量避免实现细节。作为GCC N4028

  

对于不支持COMDAT或弱符号的目标,大多数具有模糊链接的实体均作为本地符号发出,以避免链接程序重复定义错误。对于内联的局部静态函数,这不会发生,但是,几乎可以肯定,拥有多个副本会破坏事情。

默认情况下,MSVC不公开任何符号。任何“外部”符号都需要使用特定于平台的__declspec(dllexport)进行显式声明。 因此,不能说Windows与C ++不兼容。这里没有违反C ++规则,因为没有任何规则。

答案 2 :(得分:1)

  

在跨边界使用内联变量时,是否可以保证内联变量的唯一性?或者仅仅是我不应该依赖的实现细节?

要确保这一点(确保所有声明实际上都相同)。

编译器显然无法检查,链接程序也不会打扰。因此,如果您对链接器说谎(通过执行上述操作),那么您将陷入困境。


好吧,因为不是每个人都明白“对链接器说谎”的意思,所以我会充实一下。

@oliv请提供this link,其中包括:

  

这些构造的重复副本[即在多个TU中声明为内联的变量]将在链接时被丢弃。

这很好,这就是我们需要的。问题是,您不知道哪个(显然,只有一个被保留,因此,通过扩展,您不知道将会是哪个)。

因此,如果它们不同,您不知道将要使用哪一个,因此最终得到的是UB(一种特别隐蔽的形式)。这就是我对链接器说谎的意思。因为,通过在不同的TU中声明不同的变量,这就是您所做的。哎呀!