【问题标题】:why initialization of static member variable is not allowed inside class but initialization of const static members is allowed?为什么类内部不允许初始化静态成员变量,但允许初始化 const 静态成员?
【发布时间】:2018-04-26 01:36:17
【问题描述】:

当我在类内声明时尝试初始化静态成员变量时,编译器按预期抛出错误,因为我们需要为类外的静态成员变量显式分配空间。我认为这对于静态 const 变量应该是相同的。但令我惊讶的是,类中静态 const 成员变量的初始化工作正常。谁能告诉我为什么普通的静态成员变量初始化不允许以同样的方式?

【问题讨论】:

  • 非常重要的背景资料:What does odr-used mean?
  • 只有 const integralenum 成员才允许以这种方式初始化

标签: c++


【解决方案1】:

我猜你的意思是

// inside class definition block
static const int a = 0;
static int b = 0;       // error 

C++ 标准 9.4.2/4,

如果静态数据成员是 const 整数或 const 枚举类型,它在类定义中的声明可以指定一个常量初始化器,它应该是一个整数常量表达式 (5.19)。在这种情况下,成员可以出现在整型常量表达式中。如果在程序中使用该成员,则该成员仍应在名称空间范围内定义,并且名称空间范围定义不应包含初始值设定项。

标准中有规定。

编辑:

正如MM指出的,上面的引用实际上不是标准所说的,正确的是C++ Standard 12.2.3.2/3

如果非易失性非内联 const 静态数据成员是整数或枚举类型,则其声明 在类定义中可以指定一个大括号或相等初始化器,其中每个初始化器子句都是 assignment-expression 是一个常量表达式 (8.20)。该成员仍应在命名空间范围内定义 如果它在程序中被 odr-used (6.2) 并且命名空间范围定义不应包含初始化程序。一个 内联静态数据成员可以在类定义中定义,并且可以指定一个大括号或相等初始化器。 如果成员是用 constexpr 说明符声明的,它可以在命名空间范围内重新声明,没有 初始化程序(此用法已弃用;参见 D.1)。其他静态数据成员的声明不应指定 大括号或相等初始化器。

【讨论】:

  • 你引用的文字没有出现在当前的C++标准中;第 9.4.2 节是关于 switch 声明的。您应该指定要引用的文件。 (最好引用latest Standard
  • @M.M 谢谢指出问题。我认为引用来自标准,因为它已经用于回答another question。我已经检查了您提供的文件并修正了我的答案。谢谢
【解决方案2】:

一个人需要一点内存空间。 const 没有 - 它们可以被硬编码。

【讨论】:

  • 不仅可以硬编码,而且必须硬编码。但是你是对的,const 值所需的空间在编译时是已知的,并计入为程序本身分配的内存中,而静态变量可以在运行时更改,因此必须在运行时分配。
  • @BrianDriscoll - 我同意 - 我尽量不要太直率
  • @Brian:什么?仅仅因为值可以改变并不意味着分配必须是动态的。 char a[4] = { f(), g(), h() } 始终正好是 4 个字节,无论确定其值需要多少工作。此外,const 对象可能需要动态初始化。
  • @BenVoigt - 我已经阅读了他的评论几次 - 我看不到“动态”这个词
  • @BrianDriscoll 静态 const 变量可能仍然需要内存地址,例如,如果在它们上使用了 & 运算符,那么您的逻辑就无法成立。此外,在这两种情况下,所需的空间在编译时都是已知的。
【解决方案3】:

类通常在头文件中声明。头文件可以多次包含在正文文件中。如果在一个类中定义了需要内存的静态成员,那么在不同的主体文件中将有该成员的不同副本。这将扼杀静态成员的想法。

另一方面,常量不使用内存并且是只编译的构造。因此在类中声明它们不会造成任何伤害。

【讨论】:

  • 类通常定义在头文件中 -.> 尝试在头文件中声明
  • 通常定义在头文件中。
  • @BenVoigt - 定义就是他们所做的。宣布是他们应该做的。因此在头文件中
  • @EdHeal:每个定义也是一个声明。通常,头文件是定义类型的正确位置。它之前可能有前向声明来解决循环依赖问题,但完整的类型定义也属于头文件,除了有限的例外,如FILE,它旨在让大多数用户将其视为不透明类型(即使这样) ,它将在私有头文件中定义并包含在对其进行操作的多个源文件中)。 Lambda 是通常仅在实现文件中定义的类型示例(并且它们未在标头中声明)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2017-12-07
  • 2015-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多