C/C++ 之内存管理
发生内存错误时,这真的是一件很让人头疼的事情。编译器无法发现这些错误,只能从代码中一点点的去查询,然后纠正,所以记录下一些常识算是温故而知新吧。
1. 内存管理的分配方式:
(1)静态存储区分配,它在程序编译的时候已经分配好,在程序的运行期间都存在。比如全局变量,static变量等。
(2)在栈中创建,比如在执行函数时,函数内的局部变量的存储单元在栈中创建,函数执行结束后就会被自动释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配内存有限。
(3)在堆中创建,亦称动态内存分配。比如c语言中的malloc/free或者C++中的new/delete。程序员自己分配内存,自己释放内存。使用灵活,当然问题也最多。
2. 常见的内存错误及建议:
(1)内存分配未成功,却使用它。通常的方式可以使用if( p != NULL)来进行判断,或者使用assert( p != NULL)进行检查。
(2)内存分配成功,却未初始化。未初始化的数组或指针,编译器会随机赋值。所以建议不要嫌麻烦,创建了任何变量,最好一一赋值。
(3)内存越界,最为明显的例子就是数组了,在for循环中数组多1的操作,相信结果大家是知道的。
(4)内存泄露,忘记释放内存。最好的方法就是针对于malloc/free或new/delete成对出现,当然偷懒的认为,程序停止了运行,动态内存会被操作系统回收,但是如果别人使用了你的代码进行其他处理,你该怎么办。
(5)释放了内存,还在使用它。最为明显的就是野指针了。不要简单的认为,我加上if判断,就算是OK了。我承认该指针的内存被释放了,但并不代表着指针就会指向NULL或者消亡吧,在释放内存后,若没有赋值为NULL,编译器会给其该指针一个无效的地址,原因就在这里。同理,对于函数返回的栈内存的指针亦是如此。
3.其它
刚才在谈及C语言中的malloc与free时,让我想到new/delete存在的理由,难道是C++的先进性吗?NO!接下来简单的了解下吧。
malloc/free是其标准库函数,而new/delete是C++中的运算符。他们都可以用于申请动态内存和释放内存。然而由于malloc/free是库函数而不是运算符,不再编译器控制的权限内,这就使得不能讲C++中的构造函数和析构函数强加于它。有个这样的例子(vs2012)可以作为参考:
class Obj
{
public:
Obj(void) { std::cout << "Init" << std::endl; }
~Obj(void) { std::cout << "Destroy" << std::endl; }
void Init(void) { std::cout << "Init" << std::endl; }
void Destory(void) { std::cout << "Destroy" << std::endl; }
};
void UseMallocFree()
{
Obj* p = (Obj*)malloc(sizeof(Obj));
if( p == NULL)
return;
p->Init();
p->Destory();
free(p);
}
void UseNewDelete()
{
Obj* p = new Obj();
if(p == NULL)
return;
delete(p);
p = NULL;
}
void main()
{
std::cout << "malloc/free:" << std::endl;
UseMallocFree();
std::cout << "\n";
std::cout << "new/delete: " << std::endl;
UseNewDelete();
system("pause");
}
输出结果如下:
该例子模拟了对象的动态内存管理,你会发现使用new/delete简单的多。^_^