编译器如何知道其他.cpp文件如何使用静态const成员?

时间:2016-09-30 01:38:25

标签: c++ static initialization const datamember

有人可以从最权威的ISO C ++常见问题解答中向我解释这个例子吗?代码如下:

// Fred.h
class Fred {
public:
  static const int maximum = 42;
  // ...
};

// Fred.cpp
#include "Fred.h"
const int Fred::maximum;
// ...

我不能得到的陈述是:

  

如果您使用Fred :: maximum的地址,例如通过引用传递它或明确说出& Fred :: maximum,编译器将确保它具有唯一的地址。如果没有,Fred :: maximum甚至不会占用进程静态数据区的空间。

编译器单独处理.cpp文件,并且不知道其他文件对当前正在处理的数据中定义的数据做了什么。那么,编译器如何决定是否应该分配一个唯一的地址呢?

原始项目位于:https://isocpp.org/wiki/faq/ctors#static-const-with-initializers

2 个答案:

答案 0 :(得分:1)

编译器不做任何决定。对于未定义static类成员的转换单元,编译器生成的对象模块包含对该符号的未解析引用。

当所有对象模块链接在一起时,链接器负责完成作业,并将引用静态符号的翻译单元中的所有未解析引用解析为具有已定义符号的单独翻译单元。

答案 1 :(得分:0)

FAQ条目说必须在一个编译单元中定义const int Fred::maximum;。但是,仅当程序的变量为odr-used时才会出现这种情况(例如,如果引用绑定到它)。

如果变量不是 odr-used ,则可以省略定义。

但是,如果变量实际上是 odr-used 但没有定义,那么它是未定义的行为,不需要诊断。通常,如果需要变量的地址但省略了定义,则优质链接器将忽略“未定义的引用”错误。

但是,您并不总是希望依赖于未定义行为的特定表现形式。因此,最好始终包含定义const int Fred::maximum;

你问题中引用的段落是为了解决潜在的程序员问题:“好吧,在某些情况下省略定义,我不能在静态数据区域中保存4个字节吗?”

它说编译器/链接器可以执行整个程序分析,并且一旦确定未使用该定义,就做出自己的优化决策以省略定义。

尽管行const int Fred::maximum;被定义为为int分配内存,但这是一个允许的优化,因为符合程序无法测量内存是否实际已分配给不是 odr-used int

该FAQ条目的作者显然希望编译器/链接器实际上可以做到这一点。

标准中关于 odr-use 的措辞旨在支持以下编译/链接模型:

  • 如果某些代码要求变量具有地址,则目标文件将包含对变量的引用。
  • 优化可能会删除一些从未调用的代码路径,等等。
  • 在链接时,当解析这些引用时,该引用将绑定到变量的定义。

它不需要编译器产生“未定义的引用”错误消息,因为这会使编译器更难以优化。另一个优化阶段可能会完全删除包含引用的目标文件的一部分。例如,如果事实证明 odr-use 只发生在从未调用的函数中。