C++基础 内置类型和类类型的默认初始化和值初始化
写在前面的话
如果定义变量时候没有指定初值,则变量被默认初始化。
但是默认初始化还有另外一个含义,在定义内置类型时由于定义变量的位置不同,有可能会不发生初始化操作(这种情况下称为默认初始化),也有可能会给定一个初值(称为值初始化)。
为了便于说明,这篇文章中都是指在没有指定初值的情况下定义变量,如:int i;
默认初始化则采用第二种说法,和值初始化相对。
内置类型的默认初始化
- 函数体内(块作用域内)定义的普通局部变量(自动变量)或者数组
发生默认初始化,此时值是未经过初始化的未定义值。使用未定义值会导致不可控的结果。而且编译器也不一定能够确定发现错误,有时候有些编译器可能会给予警告。
fun()
{
int i; // i未经过初始化,值未定义,不能直接使用
}
内置类型的值初始化
- 定义全局变量和数组,(包括全局静态变量,数组)
- 定义局部静态变量和数组
- 内置类型的数组进行初始化时,提供的初始值数量小于数组的大小时
内置类型变量进行值初始化时均初始化0。
//全局变量均进行值初始化
int i = 0; //i = 0;
static int j = 0; //j = 0
int arrar1[5]; //arrar1[0..4] 都为0
static int arrar2[5]; //arrar2[0..4] 都为0
void printBlock()
{
int i1; //i1为自动对象,未定义值,默认初始化
static int i2; //i2局部静态变量,为0,参见值初始化2
int array1[5]; //arrary1[0..4] 都为未定义值
static int array2[5]; //arrary2[0..4] 都为0,参见值初始化2
int array3[5] = {}; //arrary3[0..4] 都为0,参见值初始化3
}
类类型进行默认初始化
- 块作用域内不使用任何初值定义一个类类型的非静态变量,此类类型的变量进行默认初始化
类类型进行值初始化
- 类类型的数组进行初始化时,提供的初始值数量小于数组的大小时,数组中国剩余的类类型变量进行值初始化
- 不使用初始值定义一个类类型局部静态变量/数组时,全局变量/数组,全局静态变量/数组。
- 在书写T()的表达式显示地请求值初始化时,(如
vector<object> vec(10) 则定义vec为含有十个值初始化的object类型的变量
)
无论类类型的变量是采用默认初始化还是值初始化均是自动执行默认构造函数,如果不能执行默认构造函数,则无法不给定初值就定义类类型变量。
那既然无论类类型是默认初始化还是值初始化都是自动执行默认构造函数,为什么还要区分值初始化和默认初始化?
这是由于无论一个类类型的成员变量是无论是类类型还是内置类型,成员变量的初始化操作都会跟随着其所在的类。如果成员所在的类发生默认初始化,则此成员变量发生默认初始化,值初始化亦然。类类型的成员变量的默认初始化和值初始化仍然是执行默认构造函数,但是内置类型的值初始化和默认初始化则遵循上面的规则(注意成员变量是否有类内初始值,或默认构造函数初始值列表进行初始化了)。
class example1
{
public:
int val3;
};
class example
{
public:
int val1;
int val2;
example1 exam;
};
//如果example发生值初始化,则定义在example中的exam成员变量发生值初始化。
//如果example发生默认初始化,则定义在example中的exam成员变量发生默认初始化。
example ex; //ex 值初始化
void printClass()
{
example ex1; //ex1 默认初始化
example exArr[2] = {}; //exArr[1],exArr[2] 值初始化
cout << "ex.val1 = " << ex.val1 << endl; //ex.val1值初始化 为0
cout << "ex.val2 = " << ex.val2 << endl; //ex.val2值初始化 为0
cout << "ex.exam.val3 = " <<ex.exam.val3 << endl; //ex.exam值初始化 ex.exam.val3值初始化 为0
cout << "ex1.val1 = " << ex1.val1 << endl; //ex1.val1 默认初始化 未定义值
cout << "ex1.val2 = " << ex1.val2 << endl; //ex1.val2 默认初始化 未定义值
cout << "ex1.exam.val3 = " <<ex1.exam.val3 << endl; //ex1.exam 默认初始化 ex1.exam.val3 默认初始化 未定义值
cout << "exArr[1].val1 = " << exArr[1].val1 << endl; //exArr[1].val1值初始化 为0
cout << "exArr[1].val2 = " << exArr[1].val2 << endl; //exArr[1].val2值初始化 为0
cout << "exArr1[].exam.val3 = " << exArr[1].exam.val3 << endl; //exArr[1].exam值初始化 exArr[1].exam.val3值初始化 为0
}
小结
这篇文章中为了说明问题,把默认初始化和值初始化表示成不同的方面。事实上很多时候将默认初始化和值初始化都归为默认初始化。对于内置类型而言,是定义一个变量但是不给定初值,定义一个类类型是直接调用默认构造函数。其具体是进行值初始化,还是没有进行初始化的未定义值要根据变量的类型,所在位置,操作来具体看待。类类型成员的初始化操作很大一部分都是在构造函数初始化列表,或者类内初始值完成的。
Recference
C++Primer 第五版