美文网首页C语言IT狗工作室C语言&嵌入式
重载C ++中的new和delete运算符

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

作者: 铁甲万能狗 | 来源:发表于2019-10-30 16:25 被阅读0次

    有时我们,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操作符,我们这里就不再展示,读者自己去尝试,只是在类外和类内定义他们函数原型这点区别。但我个人是对全局重载是有所保留的,因为这样会印象到其他类类型的内存分配和垃圾回收等默认的操作。所以除非你自己清楚自己是在做什么,否则不要滥用全局重载操作符。

    相关文章

      网友评论

        本文标题:重载C ++中的new和delete运算符

        本文链接:https://www.haomeiwen.com/subject/omyovctx.html