【问题标题】:Why isn't the one definition rule abandoned for C++17?为什么没有放弃 C++17 的单一定义规则?
【发布时间】:2019-02-08 14:17:16
【问题描述】:

引用 C++ 草案 N4713:

每个程序都应该包含每个非内联的定义 函数或变量在该程序之外的 odr 中使用 废弃的声明(9.4.1);无需诊断。定义 可以在程序中显式出现,可以在标准中找到 或用户定义的库,或(在适当时)它是隐式的 定义(见 15.1、15.4 和 15.8)。内联函数或变量 应在使用 odr 的每个翻译单元中定义 在被丢弃的语句之外。

在 C++17 之前的 C++ 版本中,我可以通过声明我的函数 inline 来绕过这个限制。 C++17 为变量添加了相同的功能。

此外,在我看来,inline-关键字除了可以忽略 ODR 之外没有其他用途。

那么,为什么不为 C++17 放弃这条规则呢?我看不到可以关闭的规则的用途。

【问题讨论】:

  • 因为如果它被放弃了,那么当您在符号中出现冲突时会发生什么?
  • @Ricardo 为什么要放弃它?
  • 你为什么要“绕过”保护你的限制?
  • 即使使用未来的模块,我们也可以打破 ODR :-/
  • 即使使用inline,多个定义的来源也必须相同,所以从这个意义上说,仍然只能有一个定义;它只是在几个翻译单元中重复。

标签: c++ c++17 one-definition-rule


【解决方案1】:

inline“关闭”ODR 不是免费的:inline 实体的定义必须存在于每个翻译单元中。请注意,这意味着对其定义的任何更改都会导致重新编译使用它的每个编译单元。当函数是许多/大型项目所依赖的某些库的一部分时,这将特别令人不快。

另一方面,非inline 函数仅存在于一个编译单元中,并在其他地方需要时由链接器通过某些符号引用。遵守 ODR 保证符号不模糊。

【讨论】:

  • ...并且该定义在所有翻译单元中必须完全相同。
  • @rustyx 是的。当然,inline 并没有真正关闭 ODR,这就是我用引号引起来的原因。尽管 IMO,inline 语义的那些确切细节在这个相对高级的 Q/A 的范围内并不真正相关,所以为了简洁和清晰起见,我宁愿跳过它们。
  • ODR 不保证符号没有歧义;它要求它没有歧义。负担在程序员身上。不必诊断 ODR 违规,它们会导致未定义的行为。一个实际的结果是,当您对“相同”函数有两种不同的定义时,您不知道将链接到哪个。
  • @PeteBecker 这可能是我的语言问题。试图修复它。
  • @BaummitAugen -- 是的,这样更好。我会留下我的评论作为阐述。
【解决方案2】:

inline 既危险又昂贵。

它很昂贵,因为现在每个使用某物的编译单元都依赖于该物的定义。所以换身体?重新编译它的每个用户。

这很危险,因为如果两个 inline 定义不一致,您的程序就是 IF-NDR(格式错误,不需要诊断)。

没有inline,两个定义会导致程序格式错误,但编译器必须提供诊断;通常是硬错误。

inline 关闭这个非常有用的警告。

如果每个编译器都能够将不同 inline 定义的 IF-NDR 转换为诊断错误消息,那么您将有更多的案例。只要这证明困难和/或未实施,inline 就是“激活不安全模式!”选项。将其设为默认值会适得其反。

【讨论】:

  • 为了解释 Yakk 的观点,inline 是昂贵的:如果程序员选择使用内联而不分析和评估性能增益,那么费用(在任何中等规模或更大的项目中)远远超过未知的性能增益(如果有的话)。对于那些可以利用 WPO 或 LTO 的可执行文件,“整个程序优化”(WPO)或“链接时间优化”(LTO)可能会使任何如此昂贵的收益变得毫无意义。避免使用inline,除非它有可衡量的好处,或者如果您的项目非常小,编译开销不是问题,或者您的时间是空闲的。
【解决方案3】:

需要权衡的是,在任何使用它的地方都需要定义 inline 函数。如果需要,只需将整个程序放在一个 .cpp 文件中即可。

ODR 是您需要进行单独编译的东西,它仍然很有用。

【讨论】:

    【解决方案4】:

    来自cppreference

    每个非内联函数或变量的一个且只有一个定义 odr-used(见下文)必须出现在整个 程序(包括任何标准和用户定义的库)。这 编译器不需要诊断这种违规行为,但行为 违反它的程序是未定义的。

    将函数声明为inline 不会“忽略” ODR,但它会导致函数的每个外观都是它自己的实体,需要在使用它的每个翻译单元中进行定义。微小但显着的差异。 ODR 仍然需要有单独的翻译单元。

    【讨论】:

      猜你喜欢
      • 2016-04-05
      • 1970-01-01
      • 2020-01-22
      • 2019-03-28
      • 2011-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多