根据http://en.cppreference.com/w/cpp/language/zero_initialization,我无法理解我班级中某个成员的确切时间和原因为零初始化。
考虑以下测试程序:
#include <iostream>
#include <stdio.h>
class MyTest {
private:
const static unsigned int dimension = 8;
void (* myFunctions [dimension])();
public:
MyTest() {}
void print() {
for(unsigned int i=0; i < MyTest::dimension; i++) {
printf("myFunctions[%d] = %p\n", i, this->myFunctions[i]);
}
}
};
int main() {
//We declare and initialize an object on the stack
MyTest testObj = {};
testObj.print();
return 0;
}
我声明一个类有一个包含签名“void functionname()”的8个函数指针的数组。当我在main
中声明并初始化类的对象MyTest testObj = {};
或MyTest testObj;
时,我预计它将被初始化为零,即所有指针都是空指针。
但是,使用g++ -m32 -o test -std=c++14 test.cpp && test
机器在我的Windows 10计算机上使用g ++ 5.3.0进行编译会得到输出:
myFunctions[0] = 76dd6b7d
myFunctions[1] = 00401950
myFunctions[2] = 0061ff94
myFunctions[3] = 004019ab
myFunctions[4] = 00401950
myFunctions[5] = 00000000
myFunctions[6] = 003cf000
myFunctions[7] = 00400080
看起来像堆栈中未初始化的值..
如果我将对象的声明移到main之外(作为全局变量),它会再次打印所有零。
如果我正确理解了cppreference,那是因为我有一个静态存储持续时间的变量,因此是零初始化的。它通过零初始化我的类的所有非静态数据成员(即myFunctions
)数组来初始化我的类类型。一个数组通过零初始化它的每个元素来初始化,在我的函数指针的情况下,它是一个空指针。
为什么当我用MyTest testObj = {};
声明它时,它不会将我的对象初始化为堆栈?
答案 0 :(得分:28)
以下
MyTest testObj = {};
对于MyTest
,不零初始化,但只是调用其默认构造函数。 cppreference 页面解释了为什么(强调我的):
作为非类类型的值初始化序列的一部分,以及没有构造函数的值初始化类类型的成员,包括未提供初始值设定项的聚合元素的值初始化。
MyTest
是类类型,a有构造函数。
使用
定义构造函数MyTest() = default;
将零初始化对象。
下面的相关标准引用(强调我的)。
来自[dcl.init#6]:
对T类型的对象进行值初始化意味着:
如果T是一个(可能是cv限定的)类类型,没有默认构造函数([class.ctor])或者是用户提供或删除的默认构造函数,那么该对象是默认初始化的;
如果T是(可能是cv限定的)类类型而没有用户提供或删除的默认构造函数,则该对象为零初始化,检查默认初始化的语义约束,如果T有一个非平凡的默认构造函数,则该对象是默认初始化的;
...
对象或类型T的引用的列表初始化定义如下:
...
否则,如果初始化列表没有元素且T是具有默认构造函数的类类型,则该对象是值初始化的。