C++的内存泄漏

学习视频

C++的两种内存分配方式

1. 栈内存

当你调用一个函数,其中局部变量就分配在栈内存上面,函数调用结束局部变量就自动释放,这个过程由编译器自动控制

一般情况下指针指向某个变量的地址,这里定义了一个变量int a,它的内存是由编译器自动分配的
然后又定义了一个指针p,指向a的地址,函数运行结束的时候,编译器会自动释放a的内存

void func()
{
	int a = 100;
	int* p = &a;//p存储了a的地址
}

2. 堆内存

堆内存用于动态分配,需要程序员手动去请求这块内存,使用完之后需要程序员手动释放,不然 这块内存就会一直存在,造成内存泄露

我们也可以用new这个关键字来动态请求一些内存,用new请求的内存,我们需要用delete手动删除, 不然不会手动释放
这里的delete是释放了p指向的内存,不是删除了p本身

void func()
{
	int* p = new int;
	delete p;
}

删除p指向的内存之后还可以把p指向别的地方

void func()
{
	int a = 100;
	int* p = new int;
	delete p;
	p = &q;
}

new不光可以请求单个元素的内存,还可以用来请求多个元素组成的数组,只需要加上方括号和元素的个数就可以;
如果用new请求了多个元素,那么delete的时候也应该加上方括号,不过不需要加上元素个数,因为编译器会帮你记住创建了多少元素

void func()
{
	int* p = new int[100];
	delete[] p;
}

内存泄露

动态分配申请内存时,需要程序员手动去请求这块内存,使用完之后需要程序员手动释放,不然 这块内存就会一直存在,别人也无法访问这块内存,就会造成资源的浪费,久而久之,内存资源就会被完全榨干,造成系统崩溃。

看一个例子,如果调用foo结束运行之后,x和y都会释放,但是p所指向的那个数组不会释放,仍然会保留下来。

void foo(int x)
{
	int y = x * 2; 
	int* p = new int[5];
	p[0] = y;
}

如果想要删除这块内存,就要用delete手动释放,如果不写delete这一行,p所指向的内存就无人问津了,因为知道这块地址的所有者p已经随着函数的结束消失了,但是p所指向的内存还空悬在那里,形成一个孤岛,别人也用不了,这个现象就叫做内存泄露,是C++最典型也是最难缠的bug之一。

void foo(int x)
{
	int y = x * 2; 
	int* p = new int[5];
	p[0] = y;
	delete[] p;
}

很多高级语言都有垃圾回收机制来解决这个问题,但C++作为追求性能到极致的语言,没有在语言层面上的垃圾回收功能,需要依靠程序员自己来管理内存的分配和释放。

补充知识点

  1. 对于一个指针不要删两次!这个属于undefined behavior
void func()
{
	int* p = new int;
	delete p;
	delete p;//wrong code!
}
  1. C++11新增了一个特性,nullptr,也就是空指针。删掉p指针之后,可以将其赋值为nullptr,这样就可以验证p是否可用;C++11之前,有的地方NULL来代替nullptr,相比NULL,nullptr是类型安全的,因为在某些情况下,编译器会把NULL和int搞混。
int *p = new int;
delete p;
p = nullptr;
...
if(p != nullptr)
{
	some code here...
}

你可能感兴趣的:(c/c++工程,c++,java,数据结构)