【问题标题】:uninitialized const未初始化的常量
【发布时间】:2011-12-26 22:03:45
【问题描述】:

使用当前的 MSVC 编译器可以完美编译:

struct Foo
{
} const foo;

但是,使用当前的 g++ 编译器编译失败:

error: uninitialized const 'foo' [-fpermissive]
note: 'const struct Foo' has no user-provided default constructor

如果我自己提供一个默认构造函数,它会起作用:

struct Foo
{
    Foo() {}
} const foo;

这是 MSVC 过于宽松的另一种情况,还是 g++ 在这里过于严格?

【问题讨论】:

  • 我无法使用任何方言选项在 GCC 4.6.1 上重现此内容。它只有在我安装一个成员变量(如int a;)时才有效,并且错误更准确:‘const struct Foo’ has no user-provided default constructor and the implicitly-defined constructor does not initialize ‘int Foo::a’
  • @KerrekSB:我所做的只是g++ foo.cpp,然后g++ --version 打印g++ (GCC) 4.6.1
  • @FredOverflow:对不起,我的意思是 GCC 4.6.2。最近更新了。

标签: c++ visual-c++ g++ constants default-constructor


【解决方案1】:

我不知道标准的确切措辞,但 g++ 中的错误似乎比什么都不说的选项更明智。考虑一下:

struct X {
   int value;
};
const X constant; // constant.value is undefined

在用户提供默认构造函数的情况下(即使它什么都不做)编译器将调用该构造函数并且对象将被初始化(通过初始化的任何定义 em> 你已经在你的构造函数中实现了)。

【讨论】:

    【解决方案2】:

    C++03 标准:

    8.5 [dcl.init] 第 9 段

    如果没有为对象指定初始化器,并且对象是(可能是 cv 限定的)非 POD 类类型(或其数组),则该对象应默认初始化;如果对象是 const 限定类型,则基础类类型应具有用户声明的默认构造函数。

    从上面看 gcc 中的错误似乎是完全有效的。

    【讨论】:

    • 注意:如果您想解释为什么 C 风格的结构隐式零初始化在 C++ 中不起作用,这是因为 C 和 C++ 实现 const 的方式不同,C++ 有 const在 C 之前。请参阅this chat transcript 了解更多信息。
    【解决方案3】:

    [2003: 8.5/9]: 如果没有为对象指定初始化器,并且 对象是(可能是 cv 限定的)非 POD 类类型(或数组 其中),对象应默认初始化;如果对象是 const 限定类型,基础类类型应具有 用户声明的默认构造函数。否则, 如果没有初始化器 为非静态对象、对象及其子对象指定,如果 任何,具有不确定的初始值; 如果对象或任何 它的子对象是 const 限定类型,程序格式错误。

    还有:

    [n3290: 8.5/11]: 如果没有为对象指定初始化器,则默认初始化该对象;如果没有初始化 执行,具有自动或动态存储持续时间的对象具有 不确定的价值。 [ 注意: 具有静态或线程存储的对象 持续时间是零初始化的,见 3.6.2._ —end note_ ]

    [n3290: 8.5/6]:默认初始化T 类型的对象意味着:

    • 如果 T 是(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化格式错误) ;
    • 如果T是数组类型,每个元素都是默认初始化的;
    • 否则,不执行初始化。

    如果程序要求对 const 限定类型 T 的对象进行默认初始化,则 @​​987654329@ 应是具有用户提供的默认构造函数的类类型。

    因此,MSVC 在这里比这两个标准都更宽松。

    【讨论】:

    • 最后应该是“允许”而不是“授权”吧?
    • @Deduplicator 与我在 IMO 的使用方式相同,但我们可以将其设为“允许”
    【解决方案4】:

    C++17 更新

    C++17 对 const 限定类类型具有默认构造函数的要求添加了一些细微差别。该标准现在定义了“const-default-constructable”概念:

    7 要默认初始化类型 T 的对象意味着:

    (7.1) — 如果 T 是(可能是 cv 限定的)类类型,则考虑构造函数。枚举适用的构造函数,并通过重载决议选择 initializer() 的最佳构造函数。如此选择的构造函数被调用,带有一个空参数列表,以初始化 对象。
    (7.2) — 如果 T 是数组类型,则每个元素都是默认初始化的。
    (7.3) — 否则,不执行初始化。

    如果 T 的默认初始化会调用 T 的用户提供的构造函数(不是从基类继承)或如果

    ,则类类型 T 是 const-default-constructible (7.4) — T 的每个直接非变体非静态数据成员 M 都有一个默认成员初始化器,或者,如果 M 属于类类型 X(或其数组),X 是 const-default-constructible,
    (7.5) — 如果 T 是具有至少一个非静态数据成员的联合,则恰好一个变体成员具有默认成员初始值设定项,
    (7.6) — 如果 T 不是联合,对于每个具有至少一个非静态数据成员(如果有)的匿名联合成员,恰好一个非静态数据成员具有默认成员初始化器,和
    (7.7) — T 的每个可能构造的基类都是 const-default-constructible。

    如果程序要求对 const 限定类型 T 的对象进行默认初始化,则 T 应为 const-default-constructible 类类型或其数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多