类成员初始化是在编译时还是在运行时进行?

101*_*010 27 c++ c++11

在C++ 11中,引入了一个新功能,程序员可以在类的定义中初始化类成员变量,请参阅下面的代码:

struct foo
{ 
  int size = 3;
  int id   = 1;
  int type = 2;
  unsigned char data[3] = {'1', '2', '3'};
};
Run Code Online (Sandbox Code Playgroud)

这个初始化是在编译期间发生的,还是这个特性只是语法糖和成员变量在默认构造函数中初始化?

Nik*_*iou 27

首先是,如前所述,它是语法糖.但是由于规则可能太难以记住,这是一个逻辑实验,可以帮助您弄清楚在编译时发生了什么,什么不是

你有你的c ++ 11类,它在类初始化器中有特色

struct foo { int size = 3; };
Run Code Online (Sandbox Code Playgroud)

另一个课程将帮助我们进行实验

template<int N>
struct experiment { enum { val = N }; };
Run Code Online (Sandbox Code Playgroud)

让我们的假设H0是初始化确实在编译时发生,然后我们可以写

foo                a;
experiment<a.size> b;
Run Code Online (Sandbox Code Playgroud)

没有运气,我们无法编译.有人可能会说失败是由于foo::size不稳定所以让我们试试

struct foo { const int size = 3; }; // constexpr instead of const would fail as well
Run Code Online (Sandbox Code Playgroud)

再次,正如gcc告诉我们的那样

'a'的值不能用于常量表达式

实验b;

或者(更清楚地)视觉工作室2013告诉我们

错误C2975:'N':'example'的模板参数无效,是预期的编译时常量表达式

因此,我们必须丢弃H0并推断初始化不会在编译时发生.

在编译时需要做些什么

有一种旧的语法可以解决这个问题

struct foo { static const int size = 3; };
Run Code Online (Sandbox Code Playgroud)

现在这个编译但要注意这在(技术上和逻辑上)不再在类初始化中.

我不得不撒谎以表达观点,但现在揭露全部真相:消息错误意味着这a是真正的问题.你看,因为你有一个对象的实例(Daniel Frey也提到了这个),所以必须初始化内存(对于成员)(在运行时).如果成员是(const)static,就像在最后一个例子中那样,它不是(ny)类的子对象的一部分,你可以在编译时进行初始化.