自动变量未显式初始化时值未定义,动态对象new无括号亦未定义;安全做法是用()或{}值初始化,或用std::vector等容器替代裸指针。

自动变量初始化:栈上分配,生命周期短,值不确定是常态
自动变量(即函数内定义的非 static 局部变量)在进入作用域时分配在栈上,退出时自动销毁。它的初始化行为完全取决于是否显式提供初值:
- 没写任何初始化器(如
int x;),就是「默认初始化」——int、double等内置类型值**未定义**,可能为任意垃圾值; - 写了
=(如int y = 42;)或()(如int z(100);)或{}(如int w{3};),就属于「直接/拷贝/列表初始化」,值确定; - 类类型自动变量(如
std::string s;)会调用默认构造函数,只要该类有可访问的默认构造函数; - 如果类没有默认构造函数,又没在定义时传参(如
MyClass obj;),编译直接报错:no matching constructor。
动态对象初始化:堆上分配,必须显式调用构造,new 后括号不能省
用 new 创建的对象生命周期由程序员控制,其初始化方式和语法约束比自动变量更严格:
-
new MyClass和new MyClass()行为不同:
前者是「默认初始化」,若MyClass有默认构造函数则调用它,否则行为未定义;
后者是「值初始化」,对内置成员强制零初始化(如int x;变成0),并调用默认构造函数(如有); -
new MyClass{}(C++11 起)等价于new MyClass(),也是值初始化; - 带参数必须用括号:
new MyClass(1, "hello"),不能写成new MyClass = {1, "hello"}(语法错误); - 数组形式如
new int[5]是默认初始化——元素值未定义;new int[5]()才是值初始化,全部为0。
容易踩的坑:int* 和 std::vector 初始化差异暴露本质
很多人以为 new int[10] 和 std::vector<int>(10)</int> 都“创建 10 个 int”,但初始化结果天差地别:
-
int* p = new int[10];→ 10 个int全是未定义值,读取任一元素(如p[0])是未定义行为; -
int* q = new int[10]();→ 10 个int全为0; -
std::vector<int> v(10);</int>→ 内部调用int()值初始化,10 个元素全为0; - 反过来,
std::vector<int> u;</int>是默认初始化,不分配空间;u.resize(10)后元素仍是未定义值——除非用u.resize(10, 0)显式填 0。
为什么 static 局部变量不算自动变量?它初始化只发生一次
static int x; 在函数内定义,但它不属于自动存储期,而是静态存储期——这点常被忽略。它的初始化发生在**第一次执行到该定义语句时**(C++11 起线程安全),且仅一次:
立即学习“C++免费学习笔记(深入)”;
- 如果没写初值(
static int x;),按静态存储期规则,自动零初始化为0; - 如果写了初值(
static int y = 42;),也只在第一次进入作用域时赋一次,后续调用函数时不再重复; - 类类型
static MyClass obj;同样只初始化一次,且若构造函数抛异常,下次进入仍会重试(C++11 起保证); - 这和自动变量每次函数调用都重新分配、重新初始化,形成根本区别。
关键点在于:自动变量的“默认初始化”几乎总是危险的,而动态对象的“无括号 new”同样危险——它们都把未定义值交到你手上。真正安全的做法,是明确使用 () 或 {} 触发值初始化,或者用容器(如 std::vector、std::array)代替裸指针。


















