重载new 和delete

new 表达式的工作机理如下:

  1. 第一步:调用一个名为operator new(或者operator new[])的标准库函数
    该函数分配一块足够大的,原始的,未命名的内存空间以便存储特定类型的对象(或者对象数组)
  2. 第二步:编译器运行相应的构造函数以构造这些对象,并为其传入初始值。
  3. 第三步:对象被分配了空间并构造完成,返回一个指向该对象的指针

delete 表达式的工作机制如下:

  1. 第一步:对对象调用析构函数
  2. 第二步:编译器调用名为 operator delete(或者operator delete[])的标准库函数释放内存空间

要重定义new和delete,就是重定义operator new 和 operator delete 这两个函数
应用程序可以在全局作用域中重定义这两个函数,也可以将他们定义成成员函数

operator new 和 operator delete的查找顺序

当编译器发现一条new和delete表达式后,将在程序中查找可用的operator new 和 operator delelte函数。如果被分配(释放)的对象是类类型,则编译器首先在类及其基类的作用域中查找这两个函数。如果该类含有operator new成员或者operator delete 成员,则相应的表达式将调用这些成员,如果不是类类型或者类中没有找到这两个函数,编译器在全局作用域中查找匹配的operator new 或者 operator delete函数,如果找到了用户自定义的版本,则使用该版本的new表达式或者delete表达式,如果仍然没有找到,则使用标准库定义的版本。

可以使用域运算符::来忽略定义在类内部的operator new 和operator delete函数,直接执行全局作用域中的版本

重定义operator new 和 operator delete

标准库定义了operator new 函数和operator delete函数的8个重载版本。其中前面4个为可能抛出bad_alloc异常,后4个版本则不会抛出异常:

void * operator new(size_t)
void * operator new[](size_t)
void  operator delete(void *) noexcept;
void  operator delete(void *) noexcept;

void * operator new(size_t, nothrow_t &) noexcept;
void * operator new[](size_t, nothrow_t &) noexcept;
void  operator delete(void *, nothrow_t &) noexcept;
void  operator delete(void *, nothrow_t &) noexcept;

应用程序可以自定义上面函数版本的任意一个。前提是自定义版本必须位于全局作用域或者类作用域中。当定义为类的成员时,它们是隐式静态的,我们无须显示地声明static,当然显示声明也不会引发错误。

重定义operator new时的注意事项

对于operator new 和operator new[]来说,返回类型必须是void *,第一个形参必须是size_t且该形参不能含有默认实参。
当编译器调用operator new时,编译器会自动把存储指定类型对象所需的字节数传给size_t形参
当编译器调用operator new[]时,传入函数的则是存储数组中所有元素所需的空间。

如果我们想要自定义operator new函数, 则可以为它提供额外的形参。此时,用到这些自定义函数的表达式必须使用new的定位形式将实参传给新增的形参 new的定位形式如下:

int *p1 = new(nothrow) int;

这个new的定位形式将调用 void * operator new(size_t, nothrow_t &)

注意:下面这个函数无论如何都不能被用户重载:
void * operator new(size_t, void *);//绝对不允许重新定义这个版本的operator new
这种形式只供标准库使用,不能被用户重新定义。这种operator new用于 定位new表达式,定位new表达式不同于new的定位形式

重定义operator delete时的注意事项

对于operator delete函数或者operator delete[]函数来说,返回类型必须是void,第一个形参的类型必须是void *.
执行一条delete表达式将调用相应的operator函数,并用指向待释放内存的指针来初始化void*形参
当我们将operator delete 或则 operator delete[]定义成类成员时,该函数可以包含另外一个类型为size_t的参数。该形参的初始值是第一个形参所指的字节数。size_t形参可以用于删除继承体系中的对象。如果基类有一个虚析构函数,则传给operator delete的字节数将因待删除指针所指对象的动态类型不同而有所区别。而且,实际运行的operator delete函数版本也由对象的动态类型决定。

标准函数库 operator new 和 operatordelete的名字容易让人误解。和其他operator函数不同,这两个函数并没有重载new表达式或delete表达式。实际上。我们根本无法自定义new表达式或者delete表达式。

一条new表达式的执行过程总是先调用operator new 函数以获取内存空间,然后在得到的内存空间中构造对象。与之相反,一条delete表达式的执行过程总是先销毁对象,然后调用operator delete函数释放对象所占空间

我们提供新的operator new函数和operator delete函数的目的在于改变内存分配方式,但是不管怎样,我们都不能改变new运算符和delete运算符的基本含义

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值