下面显示的片段在Coliru和Ideone中编译,但根据iso§8.5p6它不应该,或者我错过了什么?

时间:2014-01-03 17:48:31

标签: c++ c++11 language-lawyer default-constructor

从C ++ 11标准§8.5p6我们有:

  

如果程序要求默认初始化a的对象   const限定类型T,T应为具有用户提供的类类型   默认构造函数。

以下代码应编译。但在Coliru和Ideone都有。

class A{};

int main() {
    const A a;
}

修改

在尝试理解这里发生的事情时,我最终得到了以下代码,这些代码编译(至少它符合标准,因为A有一个用户提供的构造函数)。但后来我想到了以下问题:哪个标准子句确保a.b.j初始化为0(参见Ideone中的代码),如下所示?

#include <iostream>
struct B { int j; B(){ std::cout << "B()" << '\n'; } };
struct A
{
    struct B b;
    int i;

    public:
    A(): i(1) { std::cout << "A()" << '\n'; }

};  

int main() {
    const A a;
    std::cout << a.b.j << '\n';
    std::cout << a.i << '\n';
}

EDIT1:

很抱歉上面的编辑,但我还没有使用过Unix。上周Dietmar Kühl提请我注意"Most UNIXes start off with zero initialized pages"这一事实。因此,正如我所想的那样,a.b.j因为初始化而不是0。事实上,我刚用VS2010编译代码,a.b.j的结果是一个酉值,正如预期的那样。因此,应忽略编辑中的问题。

但我很想知道clang ++或g ++是否也会为第二个片段显示错误。谢谢。

2 个答案:

答案 0 :(得分:4)

在研究了初始化和汇总的规则后,我得出结论,你是对的 -

您的编译器正在使用快捷方式,因为没有成员,因此不需要初始化几乎。 (有趣的是,the ancient GCC 4.1.2 rejects the program。)

不幸的是我没有什么可引用的,因为在这种情况下根本没有规则覆盖[C++11: 8.5/6]

至于为什么标准不允许这样做,为什么要这样呢?空类几乎没有用,我看不出有理由为这个边缘情况积极地为更广泛,更有用的rule写一个豁免。

答案 1 :(得分:1)

考虑到第7.1.6.1节第2段第2段中的注释:cv-qualifiers,其中有以下内容:

  

2 [注意:声明变量const会影响其链接(7.1.1)   及其在常量表达式中的可用性(5.19)。如8.5中所述,   const限定类型的对象或子对象的定义必须   指定初始值设定项或进行默认初始化。 -结束   注意]

似乎确实编译器确实很奇怪。

虽然如果要添加数据成员,代码将不会在ideone中编译,但至少会在MS VC ++ 2010中编译。 在您提供的报价中,没有任何关于数据成员的说法。