为什么const成员结构中需要构造函数?

时间:2014-07-24 20:47:21

标签: c++ c++11

我有类似的代码:

class AClass {
public:
  struct AStruct { };

  AClass(){}

private:
  const AStruct m_struct;
};

int main() {
  AClass a;
}

它会抛出此编译错误(使用Clang LLVM版本5.1):

error: constructor for 'AClass' must explicitly initialize 
       the const member 'm_struct'

如果我为struct AStruct指定了C ++ 11默认构造函数,我会得到同样的错误:

  struct AStruct {
    AStruct() = default;
  };

但是,这可以通过编写一个空体的构造函数来解决:

  struct AStruct {
    AStruct(){}  // fixed
  };

为什么我需要指定一个空构造函数?它不是通过结构的公共访问自动创建的吗?

为什么C ++ 11默认构造函数不能解决问题?

2 个答案:

答案 0 :(得分:27)

来自§8.5[dcl.init] / 7:

  

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

AClass的默认构造函数默认初始化const成员(见下文),因此该成员必须具有用户提供的默认构造函数。使用= default不会导致用户提供的默认构造函数,如§8.4.2[dcl.fct.def.default] / 4中所示:

  

如果函数是用户声明的,并且未明确默认,则用户提供该函数   删除了第一份声明。


根据§12.6.2[class.base.init] / 8默认初始化成员:

  

在非委托构造函数中,如果给定的非静态数据成员或基类未由mem-initializer-id指定(包括没有mem-initializer-list的情况,因为构造函数没有ctor -initializer)并且实体不是抽象类的虚拟基类(10.4),然后是

     

- 如果实体是具有支撑或等于初始化程序的非静态数据成员,则按照8.5中的规定初始化实体;
   - 否则,如果实体是匿名联合或变体成员(9.5),则不执行初始化;
   - 否则,实体默认初始化(8.5)。

答案 1 :(得分:17)

从@ chris的答案中被盗我们有这一段:§8.5[dcl.init] / 7:

  

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

然后我们可以构建一个完全荒谬的案例来说明这种限制:

struct Foo {};
int main() {
  const Foo f;
}

无法按照标准规定在clang中编译。您的代码就是这样,但作为另一个类/结构的成员变量。

我们甚至可以这样做:

struct Foo {int x = 3;};
int main() {
  const Foo f;
}

显然所有数据都已初始化。最后一个例子让我相信这是标准中的缺陷。

这个想法可能与POD类型未初始化和const有关,但是措辞阻止了与之无关的代码。现代C ++中的默认构造函数通常都足够好,并且强制Foo(){}形式不佳。