第十六章 内存管理(1)====高质量程序设计指南C/C++编程

内存分配方式:

                 1.从静态存储区分配,内存在程序编译的时候就已经分配好了(即已经编址),这些内存在程序的整个运行期间都存在,如全局变量,static变量等。

                 2.在堆栈上分配,在函数执行期间,函数内部变量(包括形参)的存储单元都创建在堆栈上,函数结束这些存储单元自动释放,堆栈清退。堆栈内存分配运算内置于处理器的指令集中,效率很高,并且一般不存在失败的危险,但是分配的内存容量有限,可能出现堆栈溢出。

                  3.从堆(heap)或自由存储空间上分配,即动态内存分配,程序在运行期间,用malloc()或者new申请任意数量的内存,程序员自己掌握释放内存的恰当时机(使用free()或delete),动态内存的生存期由程序员决定,使用灵活、


常见的内存错误:

  1.内存尚未分配成功,却使用了。   检查指针是否为空

                  2.内存分配成功,但是尚未初始化就使用它    任何的分配需要初始化

                  3.内存分配成功已经初始化,但是访问越过了内存的边界。 如数据的越界访问

                   4.忘记释放内存或者只是释放了一部分的内存,导致内存泄露。 malloc() free()   new delete 使用必须配对

                   5.释放了内存却还在使用。  注意将已经释放的内存设置为NULL,防止产生野指针。 多次释放同一块内存出现错误。 double free

    

几点规则:

              1.用malloc()或者new申请内存之后,应该立即检查指针值是否为NULL或者进行异常处理,以防止使用值为NULL的指针。

              2.不要忘记初始化指针,数组和动态内存,防止将未初始化的内存作为右值使用。

               3.避免数组下标访问越界。

              4.动态内存的分配和释放必须配对,防止内存泄露。

              5.释放内存后应该立即把指针设置成NULL,防止野指针。


指针参数如何传递内存:
               1.指针作为参数进行内存的分配,传递指针的指针,或者传递指针的引用。因为实参是拷贝一份传递给形参。

                

void getmemory(char** p,int num)
{
    *p=(char*)malloc(sizeof(char)*num);
}

void getmemory(char*& p,int num)
{
    p=new char;
}

              2.用函数返回值传递来申请内存

char* getmemory(int num)
{
    char* p=NULL;
    p=(char*)malloc(num*sizeof(char));
    return p;
}
   

                3.注意不可以返回局部变量的地址

char* getmemory(int num)

{
    char* p="hello world";
    return p;
}
char* getmemory()
{
    char p[]="hello world";
    return p;
}
第一种 返回常量存储区的地址OK 第二种错误!!


内存释放:

         

#include <iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

int main()
{
    int* p=new int(5);
    if(p==NULL) throw 1;
    cout<<p<<endl;
    delete p;
    cout<<p<<endl;
    return 0;
}

指针被释放后其指向的地址内人不变,(不等于NULL),但是该地址对应的内存是垃圾------>p成了一个野指针。 所以必须进行设置成NULL


经典:指针消亡了,并不代表它所指的内存会被自动释放  AND  内存被释放了,并不表示指针会消亡或者成了NULL。

野指针:

           1.未初始化指针变量,任何指针在初始化时不会自动成为NULL指针,它会乱指一气,所以指针变量创建的同时应该初始化,或者设置成NULL。

           2,.指针p被释放后,未设置为NULL。

           3.指针变量超越了变量的作用范围。

class A{
public:
     void func(void){cout<<"A::func"<<endl;}
     ~A(){cout<<"~A()"<<endl;}
};
int main()
{
    A* p=NULL;
    {
       A a;
       p=&a;//注意a的生命期
    }
    p->func();//p是野指针
    return 0;
}
上述代码: 根本原因是a虽然退栈,但是仅仅是调用了析构函数,并没有清除a的内存(a的内存仍然在函数堆栈上),所以结果没有错。


MALLOC FREE AND NEW DELETE

maloc,free为C语言的库函数,而不是运算符。 new delete是运算符而不是库函数

用malloc,free函数进行对象的动态内存管理,不能调用构造函数和析构函数。必须程序员自己写函数来完成初始化和清除的工作。

new.delete会自动的调用构造和析构函数来进行调用。

某些情况下,malloc/free效率更高。用户可以自定义类重载 new/delete实现个性的内存分配和释放策略。

注意:如果使用free()来释放new创建的对象,那么该对象可能会无法执行析构函数而导致程序出错, C++并不保证new的底层会用malloc(),而且在一些实现中,malloc和new使用不同的堆,同样,用delete释放malloc申请的动态内存,理论是程序不会出错,但是该程序的可读性会很差。

p==NULL free多次都没事,但是p!=NULL,多次释放会出现错误




发布了37 篇原创文章 · 获赞 2 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章