C++ 变量的初始化问题

介绍

在C++语言中int a;表示声明了整型a但未初始化,而C++中的对象总是会被初始化的,无论是否写了圆括号或者是否写了参数列表,例如:

int basic_var;      // 未初始化:应用"默认初始化"机制
CPerson person;     // 初始化:以空的参数列表调用构造函数

参考链接: C++手稿:哪些变量会自动初始化?

默认初始化规则 定义基本数据类型变量(单个值、数组)的同时可以指定初始值,如果未指定C++会去执行默认初始化(default-initialization)。 那么什么是”默认初始化”呢?

  • 栈中的变量(函数体中的自动变量)和堆中的变量(动态内存)会保有不确定的值;
  • 全局变量和静态变量(包括局部静态变量)会初始化为零(它们存储在进程的BSS段(这是全零的一段内存空间))。

C++11: If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an ? object with automatic or dynamic storage duration has indeterminate value. Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2.

所以函数体中的变量定义是这样的规则:

int i;                    // 不确定值
int i = int();            // 0
int *p = new int;         // 不确定值
int *p = new int();       // 0

几种初始化情况对比

全局变量(全局静态变量) Vs 局部变量(局部静态变量)

全局变量,全局静态变量和局部静态变量是存放在BSS段的,所以默认初始化为 0。局部变量是在栈里面,所以初始化情况不确定。

类成员变量初始化

可见内置类型的成员变量的”默认初始化”行为取决于所在对象的存储类型,而存储类型对应的默认初始化规则是不变的。 所以为了避免不确定的初值,通常会在构造函数中初始化所有内置类型的成员。

嵌套类的变量初始化

规则还是是一样的,默认初始化行为取决于它所属对象的存储类型。封闭类(Enclosing)中成员对象的内置类型成员变量的”默认初始化”行为取决于当前封闭类对象的存储类型,而存储类型对应的默认初始化规则仍然是不变

代码例子

#include <iostream>

//1. 全局变量与静态全局变量
int g_var;
int *g_pointer;
static int g_static;


class A{
public:
    int v;
}; 

class B{
public:
    int v;
    A a;
};

//2. 全局成员变量
A class_g_var;
B class_b_g_var;

int main(){
    //1. 局部变量与静态局部变量
    int l_var;
    int *l_pointer;
    static int l_static;

    // 2. 具备成员变量
    A class_l_var;
    static A class_l_static;

    B class_b_l_var;

    std::cout<<"--------Global Vs Local Variate---------"<< std::endl;
    std::cout<<"Global Variate: "<< g_var << std::endl;
    std::cout<<"Global Point: "<< g_pointer << std::endl;
    std::cout<<"Global Static Variate: "<< g_static << std::endl;

    std::cout<<"Local Variate: "<< l_var << std::endl;
    std::cout<<"Local Point: "<< l_pointer << std::endl;
    std::cout<<"Local Static Variate: "<< l_static << std::endl;

    std::cout<<"--------Global Vs Local Class Variate---------"<< std::endl;
    std::cout<<"Global Class Variate: "<< class_g_var.v << std::endl;
    std::cout<<"Local Class Variate: "<< class_l_var.v << std::endl;
    std::cout<<"Local Static Class variate: "<< class_l_static.v << std::endl;  

    std::cout<<"--------2lGlobal Vs Local Class Variate---------"<< std::endl;
    std::cout<<"Global Class Variate: "<< class_b_g_var.v << "  " << class_b_g_var.a.v << std::endl;
    std::cout<<"Local Class Variate: "<< class_b_l_var.v << "   " << class_b_l_var.a.v <<std::endl;

    return 0;  
};

Makefile

CXX = g++

# Warnings frequently signal eventual errors:
CXXFLAGS=-g -std=c++11 -W -Wall -Weffc++ -Wextra -pedantic -O0

OBJS = \
	main.o
EXEC = run

%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@

$(EXEC): $(OBJS)
	$(CXX) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS)

main.o: main.cpp

clean:
	rm -rf $(OBJS)
	rm -rf $(EXEC)
Terry Tang
Terry Tang
Software Development Engineer

My research interests include distributed robotics, mobile computing and programmable matter.

comments powered by Disqus

Related