6.2 new 和 delete 运算符

来源:互联网 发布:php单选框提交 编辑:程序博客网 时间:2024/04/25 17:56

Q1:new运算符

• new运算符是由两个步骤组成

1. 通过适当的new运算符函数的实例,配置所需要的内存

2. 给配置得来的对象设立初值

Eg:

        int * pt = new int(5);        //实际操作如下:        int * pt;        if(pt = _new(sizeof(int)))            *pi = 5;    //通过构造函数配置类对象的方式相同:        Point * pt = new Point;        //实际操作如下:        Point * pt;        if(pt = _new(sizeof(Point)))            pt = Point::Point(pt);

• 要求每一次new的调用都必须传回一个独一无二的指针,因此哪怕new申请的空间是0,也会分配一个字节的内存空间,用来返回独一无二的指针

*注:在g++中,new int(0),将返回一个唯一的非空指针,其中存放 “\0”,可用来释放
*注:在VS中,new int(0)将返回一个唯一的非空指针,其内容未定义,可用来释放

• new运算符实例的实现:(通过malloc实现内存分配)

    extern void * operator new(size_t size)    {        if(size ==0)            size = 1;            //用来确保返回的是独一无二的非空指针        void * last_alloc;        while(!(last_alloc = malloc(size)))        {            if(_new_handler)      //允许用户提供属于自己的_new_handler()函数,自行进行内存分配                (*_new_handler)();            else                return 0;        }        return last_alloc;    }




Q2:delete运算符

• delete运算符也分为两个步骤:

  1. 若是类类型,则需要先调用析构函数销毁对象

  2. 释放内存空间

Eg:

        int * pt = new int(4);        delete pt;        //实际执行操作如下:        if(pt != 0)            _delete(pt);    //对类类型指针,先调用析构函数        Point * pt = new Point;        delete pt;        //实际执行操作如下:        if(pt != 0)        {            Point::~Point(pt);            _delete (pt);        }

• delete 作用在指针上后,该地址上的对象不再合法,但是该地址仍然是合法的

• delete 运算符也是以标准的C free()实现的:

    external void operator delete(void * ptr)    {        if(ptr)        {            free((char *)ptr);        }    }




Q3:new与 malloc的区别:

1. 性质上:new 是运算符,malloc是函数

2. 功能上:new 分配内存空间并初始化该空间,malloc仅分配内存空间

3. 实现上:new 通过malloc分配空间,malloc即为分配空间的函数




Q4:针对数组的 new 语意

• 当用 new 定义内置类型数组或POD类型数组,new 操作只是简单的内存分配与释放操作,将不会调用vec_new()函数(该函数功能是把默认构造函数作用于数组中每个元素之上)

Eg:

    int * p = new int[5];            //真实操作如下:            int * p = (int*)_new(5 * sizeof(int));

• 如果类定义了默认构造函数,则vec_new()就会被调用,配置并构造类对象组成的数组

Eg:

        Point * p = new Point[10];        //真实操作如下:        Point *p;        p = vec_new(0, sizeof(Point), 10, &Point::Point(), &Point::~Point());

• 在构造类类型数组过程中,如果想要进行异常处理,需要将析构函数传送给vec_new(),因为如果构造过程中出错,需要将已构造的对象析构并释放,然后才抛出异常

• 出于效率考虑,在调用 delete 运算符时,需要指明维数(但不需要指明元素个数),否则,运算符将该指针作为一个对象看待,并释放该数组中的第一个元素,而其他元素仍然存在

• new 操作返回的指针应记录元素个数,记录元素个数有两个方法:

  1. cookie:为vec_new()所传回的每一个内存块配置一个额外的word,把元素个数放在这个word中

  2. 维护一个“联合数组”:该数组中放置指针及其大小

• 对派生类而言:

Eg:

            Point * ptr = new Point3d[10];            delet ptr;

希望delete 操作调用 Point 和 Point3d 的析构函数各十次。

施行于数组上的析构函数,是根据交给vec_delete()函数的“被删除的指针类型”来调用析构函数的。

    *因此,对上例中,将只调用 Point::~Point()

• 只能在程序员层面进行手动调用,而不是依赖语言执行

        for(size_t i(0);i < elem_cnt;++i)        {            Point3d * p = (Point3d*)(&(ptr[i]));            delete p;        }




Q5:Placement Operator new的语意

• placement new是重载operator new的一个标准、全局的版本,它不能被自定义的版本代替(不像普通的operator new和operator delete能够被替换成用户自定义的版本)。

• placement new 需要第二个参数,类型为 void*,其函数原型如下:

    void * operator new(size_t,void *p)    {        return p;    }

• 使用实例:

Eg:

            Point * pt = new Point;            Point * ptn = new(pt)Point;

上述代码将 pt 所指的内存空间放置新产生的 Point 对象,new运算符新增的参数是用来指定内存空间的

• placement new 运算符的功能:既能决定对象放置在哪里,也能保证会执行对象的构造函数

Eg:

            Point * ptn = new(pt)Point;            //实际操作如下:            Point * ptn = (Point*)(pt);            if(ptn != 0)                ptn = Point::Point(ptn);

• 需要注意:如果 placement operator 在原已存在的一个对象上构造新的对象,哪怕该对象定义了析构函数,也不会调用其析构函数,需要程序员手动调用

• 指定的内存块的指针类型:要么与新分配对象同类型,要么是新鲜的内存

注:新鲜内存的定义方式:char p = new char[sizof(Point)];

• 对派生类需要注意:

Eg:

        struct T        {            int j;            virutal void f();        }        struct TT : public T        {            virtual void f();        }        //注意:此时 T 与 TT 所占空间大小相同        T b;        b.f();  //调用T::f();        b.~T();        new(&b)TT;         //在 T 与 TT 所占空间相同时才不会报错        b.f();  //编译器仍然调用 T::f(),而不是TT::f()
0 0