【问题标题】:Basic fun with static const integral members静态 const 积分成员的基本乐趣
【发布时间】:2023-03-28 04:28:01
【问题描述】:

考虑以下代码:

struct X {
  static const int i = 45;
};

void foo() {
  const int* k = &X::i;
}

int main() {
}

如果不打开您最喜欢的编译器,您认为尝试编译和链接这个简单的野兽会产生什么结果?

有些人可能会感到惊讶,它不仅取决于编译器,还取决于它的优化选项!例如,在 gcc 上,代码将拒绝在优化关闭的情况下链接,但会很乐意在任何优化打开的情况下链接(并生成可运行的无操作可执行文件)。

失败案例中的诊断会很有趣-找不到符号X::i。启用优化的链接会成功,因为X::i 将被丢弃。

还有问题。 编译这段代码是编译器的正确行为吗?由于X::i 没有链接,当被要求生成一个要求该符号链接的代码时,编译器不应该抱怨吗?

【问题讨论】:

  • 你是 odr-using i 所以它必须被定义,如果你不这样做就不需要诊断
  • @ShafikYaghmour 我没有看到评论中缺少任何作为答案的内容?
  • @curiousguy 我认为 odr 标签更好,它肯定更具可读性。我投票决定将其设为 odr 标签的同义词。虽然它没有那么旧,但奇怪的是我以前从未注意到它。
  • 对于未定义行为的代码没有正确的行为。
  • @M.M NDR 和 UB 并不完全相同,如果我理解正确,NDR 通常是针对编译时问题,而 UB 是针对运行时问题。

标签: c++ compiler-errors language-lawyer one-definition-rule


【解决方案1】:

既然你是odr-usingi,通过获取它的地址,它必须在类之外定义:

const int X::i ;

违反此规则属于无需诊断类别,因此这是完全有效的行为:

非正式地,如果一个对象的地址被占用,或者一个对象是 odr-used 引用绑定到它,如果一个函数是 odr-used 调用它或获取它的地址。如果一个对象或一个函数 是odr-used,它的定义必须存在于程序的某个地方;一种 违反这是一个链接时错误。

这可能取决于编译器、优化级别等...

C++ 标准部分草案3.2 [basic.def.odr] 说:

每个程序都应包含每个非内联的确切定义 在该程序中使用 odr 的函数或变量;没有诊断 必填

一些注意事项:

  • 一般来说,捕获 odr 违规行为是 hard problem
  • 在这种情况下,捕捉它并不像看起来那么简单,因为i 可以在稍后或在另一个翻译单元中定义。
  • 我们想要不符合规则的定义,因为我们只想要一个定义,而声明可以重复,即如果它们是头文件的一部分。

【讨论】:

  • 我相信,在这种情况下,至少要求一个警告不会太多吧?这会在成功发布时破坏调试版本,当然,在更大的代码库上会产生令人不快的影响......但这回答了我的问题,谢谢。
  • 我知道在一般情况下很难。但在这种特殊情况下,我没有看到任何困难。编译器非常清楚我不应该获取静态 const i 的地址。
  • @SergeyA 它可以在稍后或在另一个翻译单元中定义。
  • 没有意识到您仍然可以将 X::i 定义为符号。我不认为 C++ 的这个特定方面对开发人员有帮助。
  • @SergeyA 这就是为什么你要从书本中学习,而不是反复试验
猜你喜欢
  • 2010-12-21
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
  • 2016-06-27
  • 1970-01-01
  • 1970-01-01
  • 2012-12-13
  • 1970-01-01
相关资源
最近更新 更多