奇怪的未初始化的常量成员行为

Weird uninitialized const member behavior

本文关键字:成员 常量 初始化      更新时间:2023-10-16

考虑以下代码片段:

struct Foo {
};
template<typename T>
struct Bar {
    const T foo;
};
int main() {
    Bar<Foo> test;
}

我正在使用 g++-4.9.2 使用 [-std=c++11 -O0 -g3 -pedantic -Wall -Wextra -Wconversion] 编译它并得到error: uninitialized const member in ‘struct Bar<Foo>’。这是很明显的。

但是尝试添加 std::string 作为 Foo 成员和程序编译!

#include <string>
struct Foo {
    std::string test;
};
// (...)

怎么回事?将测试的类型替换为双重会导致程序无法再次编译。类中的字符串成员发生了哪些变化?

链接到包含此代码段的联机编译器。

自 4.6 版以来,gcc 的行为似乎就是这样。

我认为它应该始终产生错误。叮当这样做。C++标准在§12.1.4的第(4.3)条中说,默认构造函数在以下情况下被隐式删除

— 任何 const 限定类型的非变量非静态数据成员(或 数组)没有大括号或等号初始值设定项没有 用户提供的默认构造函数,

由于Foo没有用户提供的默认构造函数,因此Bar应该有一个隐式删除的默认构造函数,因此在 main 中实例化Bar<Foo> test应该会产生错误。

也许向 GCC 报告错误?

如果您的类/结构中有const数据成员,则编译器不会为此生成默认构造函数。您必须显式定义它并初始化该const成员(而不是分配它)。

在这两种情况下,这都应该是一个错误。

看起来 g++ 会自动生成一个默认构造函数,即使 const 成员应该在构造时初始化,因为它知道字符串有一个默认构造函数将其初始化为空字符串。事实上,一切都发生得好像来源是:

struct Foo {
    std::string test;
    Foo():test() {;}
};
template<typename T>
struct Bar {
    const T foo;
    Bar(): foo() {;}
};
int main() {
    Bar<Foo> test;
}

它使用 clang 和 MSVC 都可以很好地编译。

(但我必须承认,我仍然没有在 gcc 文档中找到解释这一点的参考......