问题描述: 在功能自测的时候发生程序崩溃,在调试的过程将问题定位到崩溃是在操作指针的地方。代码示例如下:
if (ptr != nullptr)
{
delete ptr;
ptr = nullptr;
}
崩溃在ptr = nullptr;
这一行代码上,而我前面定义了该指针int* ptr;
并未对其进行new
相关的操作和初始化,那既然ptr
并不是nullptr
,那为何delete
该指针后会导致程序崩溃呢?
原因分析: delete
指针操作只是释放指针原本所指的内存,并没有删除该指针,如果该指针没有进行new
相关的操作和初始化,也就是没有进行申请内存的操作,且指针指向了一个随机值,因此ptr
不是 nullptr
,如果执行delete
操作会导致程序崩溃。
思维拓展: 如果不进行delete ptr; ptr = nullptr;
这两行代码操作程序会崩溃吗?在VC++
中,程序在Release
模式下输出000000000000000A
,而在Debug模式下输出CCCCCCCCCCCCCCCC
,说明未初始化的指针指向的是一个随机的地址,在未初始化下对指针执行写操作,也有可能会使程序崩溃,比如指向随机的地址恰好有内容,就会把之前的内容给覆盖掉,也会引起系统崩溃。
解决方案: 没有进行new
操作,就不要进行delete
操作。其次指针一定要进行初始化,将指针初始化为某个变量的地址,或者初始化为空指针,如下:
int temp =10;
int* ptr = &temp; //将指针初始化为temp变量的地址
int *ptr = nullptr; //初始化为空指针
如果是对new
出来动态内存的指针进行初始化呢?如下:
int* p1 = new int; //指向了一个未被初始化的int空间
int* p2 = new int(); //指向了一个被初始化的int空间,其值为0
int* p3 = new int(1); //指向了一个被初始化的int空间,其值为1
// define class A;
A* p4 = new A; //指向了一个调用了默认构造函数的实例A,除非A的默认构造函数对A的成员进行初始化,否则A的成员全为未初始化变量
A* p5 = new A(); //指向了一个调用了默认构造函数的实例A,若A自定义了默认构造函数,A的成员变量初始化依赖于自定义的默认构造函数,反之A的成员变量全为初始化后的变量
A* p6 = new A[10]; //指向了一个调用调用了默认构造函数的实例A的数组,执行结果同p4
A* p7 = new A[10](); //指向了一个调用调用了默认构造函数的实例A的数组,执行结果同p5
在平时写代码的过程中,对于一块新申请的内存需要先进行初始化再去用它,一般是例如p3
的直接初始化或者用memset
函数。不同new
的用法对应的初始化的逻辑总结如下:
new A | new A() | new A(parameters) | |
---|---|---|---|
A 为内置类型 | 无初始化动作 | 进行值初始化,若A 为int 类型,则初始化为0 | 进行值初始化,A 被初始化为parameters |
A 为calss/struct | 调用默认构造函数,A 中成员是否初始化依赖于默认构造函数的实现。 | 若自定义了默认构造函数,则调用自定义的默认构造函数。否则调用系统默认构造函数,并对A 中的成员进行值初始化。 | 调用A 的自定义构造函数 |