重载C ++中的new和delete运算符

有时我们,C++编译器提供的默认版本的new和delete运算符,无法在他们执行操作之前,对被操作的对象的数据成员执行一些自定义的逻辑操作,那么我们此时就需要考虑重载C ++中的new操作符和delete操作符。 它们操作符可以全局重载,也可以在特定类中重载。

首先我们为什么要重载new / delete操作符?

  1. 可以在重载新的运算符功能中添加异常处理例程。
  2. 希望自定义运算符delete,以用0覆盖被回收的堆内存块,以提高应用程序数据的安全性(下文示例会提及)
  3. 重载new操作符可以在其内部定义C版本的malloc或realloc函数进行对象的堆内存分配,然而C++并不建议你这样做,因为这样已经绕过了标准库中默认的内存分配器的内存管理机制。
  4. 同理delete操作也可以在其重载版本中定义C版本的free()函数,同样C++是不建议这么做。

new / delete 操作符的作用域

  • 如果使用某个类的成员函数来重载这些运算符,则意味着这些运算符仅针对该特定类才被重载。
  • 如 果重载是在类外完成的(即它不是类的成员函数),则只要您使用这些运算符(在类内或类外),都将调用重载的“ new”和“ delete”。 这是全局超载。

以下是new操作符函数的原型

void* operator new(size_t size);

以下是delete操作符函数的原型
delete操作符必须匹配一个void*类型的参数,函数返回的类型是void,并且默认情况下,重载后的new和delete操作符函数都是静态成员,因此在函数内部是无法使反问this指针

void operator delete(void*); 

该函数接收一个必须删除的void *类型的参数。 函数不应该返回任何东西。
注意:默认情况下,重载的new和delete运算符函数都是静态成员。 因此,他们无权访问此指针。

重载类内部的delete操作符

下面是一个关于Person类的个人信息的例子,我们在Person类内部重载了delete操作符

class Person{
    double d_height;
    size_t d_age;
    std::string d_idNo;
    std::string d_name;
    bool d_secur=false;
    
public:
        Person(std::string& name,size_t age,double height,
                        std::string id,bool secur=false)
        :  
         d_name(name),
        d_age(age),
         d_height(height),
         d_secur(secur),
         d_idNo(id)
        {}

        void show(){
                std::cout<<"姓名:"<<d_name<<std::endl;
                std::cout<<"年龄:"<<d_age<<std::endl;
                std::cout<<"身高:"<<d_height<<std::endl;
                std::cout<<"身份证:"<<d_idNo<<std::endl;
        }

        void set_height(double height)
        {
            if(height>=0){d_height=height;}
        }

        void set_age(size_t age){
             if(age>0){d_age=age;}
        }

        void operator delete(void* var){
          Person *tmp=static_cast<Person*>(var);
          if(tmp==nullptr){
             std::cout<<"该对象不存在,请勿重复delete操作!!"<<std::endl;
             exit(0);
          }
          if(tmp->d_secur){
             std::cout<<"delete前对用户敏感信息重置为默认值"<<std::endl;
             tmp->d_name="";
             tmp->d_age=0;
             tmp->d_height=0;
             tmp->d_idNo="";
             tmp->show();
          }
          ::operator delete (var);
          var=nullptr;
       }

};

上面的重载delete操作符默认是一个静态函数,因此我们没有使用Person对象的this指针,那么我们需要在delete operator函数内部在delete之前,我们需要对被delete的对象内部的数据进行一些重置操作,该怎么办?
正如例子所示,我们使用函数原型中的void*指针参数进行类型转换为tmp临时变量,用该临时变量来重置我们Person对象内部的数据成员

Person *tmp=static_cast<Person*>(var);

然后,我们还有一些辅助方法用于修改Person对象的信息,并且在之后显式调用delete销毁Person对象

void do_something(Person **s,double k){
   if(*s==nullptr){
      std::cout<<"对象不存在,操作失败"<<std::endl;
      exit(0);
   }
   (*s)->set_height(k);
   (*s)->show();
   
   delete *s;
   *s=nullptr;
}

调用代码

int main(void){
   std::string name="Kali";
   std::string idnum="4738348-3848-2345";
   Person *st=new Person(name,19,95,idnum,true);
   Person *tmp=st;
   
   std::cout<<"st指向的堆内存地址:"<<st<<std::endl;
   do_something(&st,72);
   std::cout<<std::endl;

   //这里中间假设有很多业务代码......
   std::cout<<"程序员不经意再次调用之前已经释放的指针变量"<<std::endl;
   std::cout<<std::endl;
   do_something(&st,64);
}

输出

sss18.png

从程序的输出我们,我们已经看到重载delete操作符的用处了,delete操作符内部,我们使用了一个Person类的指针变量,在被内存释放前,该临时变量修改它指向堆中的内存块的数据,并且也通过“::”作用域操作符再次调用全局的operator操作符,如下代码所示

 ::operator delete (var);

最后对传入指针变量重置为nullptr,这样做的目地是为了防止该指针变量沦为幽灵指针,关于“幽灵指针”是设计内存泄漏的话题,我会在另外文章中详述。

后记:

  • 关于全局重载new / delete操作符,我们这里就不再展示,读者自己去尝试,只是在类外和类内定义他们函数原型这点区别。但我个人是对全局重载是有所保留的,因为这样会印象到其他类类型的内存分配和垃圾回收等默认的操作。所以除非你自己清楚自己是在做什么,否则不要滥用全局重载操作符。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • C++运算符重载-下篇 本章内容:1. 运算符重载的概述2. 重载算术运算符3. 重载按位运算符和二元逻辑运算符4...
    Haley_2013阅读 5,320评论 0 49
  • C++语言的一个很有意思的特性就是除了支持函数重载外还支持运算符重载,原因就是在C++看来运算符也算是一种函数。比...
    欧阳大哥2013阅读 7,606评论 0 8
  • new和delete的内部实现 C++中如果要在堆内存中创建和销毁对象需要借助关键字new和delete来完成。比...
    欧阳大哥2013阅读 18,992评论 1 16
  • C++运算符重载-上篇 本章内容:1. 运算符重载的概述2. 重载算术运算符3. 重载按位运算符和二元逻辑运算符4...
    Haley_2013阅读 6,809评论 0 51
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 13,149评论 1 51