zoukankan      html  css  js  c++  java
  • c/c++ 重载new,delete运算符 placement new

    重载new,delete运算符

    new,delete在c++中也被归为运算符,所以可以重载它们。

    new的行为:

    • 先开辟内存空间

    • 再调用类的构造函数

    开辟内存空间的部分,可以被重载。

    delete的行为:

    • 先调用类的析构函数

    • 再释放内存空间

    释放内存空间的部分,可以被重载。

    为什么要要重载它们?

    有时需要实现内存池的时候需要重载它们。频繁的new和delete对象,会造成内存碎片,内存不足等问题,影响程序的正常执行,所以一次开辟一个适当大的空间,每次需要对象的时候,不再需要去开辟内存空间,只需要调用构造函数(使用placement new)即可。

    new,delete的重载函数,可以是全局函数,也可以是类内部的公有重载函数;当既有全局的重载函数,也有类内部的公有重载函数时,实际调用的是类内部的公有重载函数。

    new,delete可以有多种重载方式,但是,new函数的第一个参数一定要是size_t类型

    重载方式1,new单个对象

    void* operator new(size_t sz){
      void* o = malloc(sz);
      return o;
    }
    void operator delete(void *o){
      free(o);
    }
    

    重载方式2,new对象的数组

    void* operator new[](size_t sz){
      void* o = malloc(sz);
      return o;
    }
    void operator delete[](void *o){
      free(o);
    }
    

    重载方式3,不开辟空间,只是调用给定对象(用地址识别)的构造方法,也叫placement new

    //第一个参数size_t即使不使用,也必须有                          
    void* operator new(size_t sz, String* s, int pos){
      return s + pos;
    }
    

    小例子:

    #include <iostream>
    #include <string.h>
    using namespace std;
    
    class String{
    public:
      String(const char* str = ""){
      cout << "Create" << endl;
        if(NULL == str){
          data = new char[1];
          data[0] = '';
        }
        else{
          data = new char[strlen(str) + 1];
          strcpy(data, str);
        }
      }
      ~String(){
      cout << "Free" << endl;
        delete []data;
        data = NULL;
      }
    private:
      char* data = NULL;
    };
    //重载方式1
    void* operator new(size_t sz){
      cout << "in operator new" << endl;
      void* o = malloc(sz);
      return o;
    }
    void operator delete(void *o){
      cout << "in operator delete" << endl;
      free(o);
    }
    //重载方式2
    void* operator new[](size_t sz){
      cout << "in operator new[]" << endl;
      void* o = malloc(sz);
      return o;
    }
    void operator delete[](void *o){
      cout << "in operator delete[]" << endl;
      free(o);
    }
    
    //重载方式3
    //第一个参数size_t即使不适用,也必须有                          
    void* operator new(size_t sz, String* s, int pos){
      return s + pos;
    }
    int main(){
      String *s = new String("abc");
      delete s;
    
      String *sr = new String[3];
      delete []sr;
    
      //开辟内存池,但是还没有调用过池里对象的构造方法                  
      String *ar = (String*)operator new(sizeof(String) * 2);
      //调用池里第一个对象的构造方法,不再开辟空间
      new(ar, 0)String("first0");
      //调用池里第二个对象的构造方法 ,不再开辟空间 
      new(ar, 1)String("first1");
      //调用池里第一个对象的析构方法,注意不会释放到内存
      (&ar[0])->~String();
      //调用池里第二个对象的析构方法,注意不会释放到内存
      (&ar[1])->~String();
      //下面语句执行前,内存池里的对象可以反复利用 
      operator delete(ar);
    
    }
    
  • 相关阅读:
    electron 显示对话框 showMessageBoxSync showMessageBox
    c++ 随机数 取值范围 多线程
    c++ 字符串转换为数字
    VS2019 C++动态链接库的创建使用(1)
    js mutationobserver property vs attribute
    Chromium base 基础库概览
    Git:合并分支----git merge命令应用的三种情景
    chromium 处理 addEventListener 事件
    JavaScript监听属性改变
    chrome 启动开关参数
  • 原文地址:https://www.cnblogs.com/xiaoshiwang/p/9515202.html
Copyright © 2011-2022 走看看