计算机系统应用教程网站

网站首页 > 技术文章 正文

C++|11种“裸指针”的内存访问与释放错误

btikc 2024-09-12 12:06:29 技术文章 12 ℃ 0 评论

是否能够直接操作内存资源,不同的程序语言有不同的选择(语法机制),有的程序语言(如C#和Java)有垃圾回收机制,而C因为效率和便利的考虑,能够通过指针操作内存资源,且无垃圾回收机制。C++延续C的效率原则,但在指针的安全使用方面做了努力,引入了引用、异常处理机制,通过new\delete封装了malloc()\free(),且在STL封装了智能指针。

标记(mark)和清扫(sweep)是一种垃圾回收方法。使用这种方法的垃圾回收器定期检查程序中的每个指针,并将指针引用的内存标记为仍在使用。在每一轮周期结束时,未标记的内存视为没有在使用,因而被释放。

a 在垃圾回收器中注册所有指针,这样就可以进行遍历操作;

b 让所有对象都从一个混入类中派生,允许垃圾回收器将对象标记为正在使用;

c 确保垃圾回收器运行时不能修改指针;

垃圾回收可能也会引发一些问题,如当垃圾回器运行时,程序可能会停止响应。析构函数具有不确定性。

对于“裸指针”,从声明、定义、分配、初始化、访问、释放、置NULL的整个过程都有可能发生错误:

// 1 访问错误
// 1.1 内存分配未成功,却使用了它
void allocatedMayFailure()
{
	int* arr = new int[1000000000]; // may return nullptr
	if(arr==NULL) return;
	arr[0] = 1;
	cout<<arr[0];
	delete[] arr;
}
// 1.2 访问非法指针
void accessInvalid()
{
	int* p = reinterpret_cast<int*>(1000);
	*p = 5; // bug, p is not a valid pointer, crash!
}
// 1.3 内存分配虽然成功,但是尚未初始化就引用它
void readUninitialized()
{
	int* p;
	cout<<*p; // bug, p is uninitialized
}
// 1.4 内存分配成功并且已经初始化,但操作越过了内存的边界
void accessElsewhere()
{
	int x, y[11], z;
	x=0;
	z=0;
	for(int i=0; i<=11; i++)
	{
		y[i] = 5; // bug for i==11, element 11 is past end of array
	}
}
// 1.5 非法访问已释放指针
void accessFreed()
{
	int* p1 = new int;
	delete p1;
	int* p2 = new int;
	*p1 = 5; // bug, the memory pointed to by p1 has been freed
}
// 2 内存释放错误
// 2.1 忘记了释放内存,造成内存泄露
void memoryLeak()
{
	int* p = new int[1000];
	return;			// Bug, not freeing p
}
// 2.2 重复释放内存错误
void doubleFree()
{
	int* p1 = new int[1000];
	delete[] p1;
	int* p2 = new int[1000];
	delete[] p1; // bug, freeing p1 twice,crash!
}
// 2.3 释放内存命令与分配内存命令不匹配
void mismatchedFree()
{
	int* p1 = (int*)malloc(sizeof(int));
	int* p2 = new int;
	int* p3 = new int[1000];
	delete p1;		// bug, should use free()
	delete[] p2;	// bug, should use delete
	free(p3);		// bug, should use delete[]
}
//2.4 因为异常机制,释放内存语句没有机会执行
class Simple
{
public:
	void go(){}
};
void leaky()
{
	Simple* p = new Simple();
	p->go();
	delete p;//如果go()抛出异常,delete得不到执行从而产生内存泄露
}
void notleaky()
{
	unique_ptr<Simple> p(new Simple()); //c+11
	p->go();
}
// 2.5 使用 free 或 delete 释放了内存后,没有将指针设置为 NULL。
 // 导致产生" 野指针"(指向的内存是已被操作系统回收的指针)。
void noNull()
{
 char* p = new char[10];
 memset(p,0,10);
 delete [] p;
	//p=NULL; // 指针释放后记得赋NULL值
 if(p!=NULL)
 {
 strcpy(p,"hello!"); // 使用悬空指针(野指针)
 cout<<p;
 }
 }
//2.6 释放堆上指针
void freeStack()
{
	int x;
	int* p = &x;
	delete p; // bug, freeing stack memory, crash!
}

-End-

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表