重载new,delete运算符

本文详细介绍了C++中new和delete运算符的重载,包括为何需要重载以及如何重载。通过重载,可以实现内存池管理,减少内存碎片并提高效率。示例代码展示了不同类型的重载方式,如单个对象、对象数组以及placement new的用法,并在实际应用中创建和销毁对象。

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] = '\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);

}
### 重载`new`和`delete`运算符C++中,可以通过重载`new`和`delete`运算符来实现对内存分配和释放的自定义控制。这种机制特别适用于需要优化性能、实现特定内存管理策略或构建对象池等场景。 #### 自定义类中重载`new`和`delete` 对于自定义类,可以在类内部定义静态成员函数`operator new`和`operator delete`,以覆盖默认的全局版本。这些函数负责分配和释放内存,并且可以被设计为支持特定需求的功能,例如日志记录、内存泄漏检测或资源池管理。 以下是一个示例,展示了如何在`Test`类中重载`new`和`delete`运算符: ```cpp #include <iostream> using namespace std; class Test { public: Test() { cout << "我是构造函数" << endl; } ~Test() { cout << "我是析构" << endl; } // 重载 new 操作符 static void* operator new(size_t t) { cout << "调用重载new" << endl; void* p = ::operator new(t); // 调用全局 new return p; } // 重载 delete 操作符 static void operator delete(void* p) { cout << "调用重载delete" << endl; ::operator delete(p); // 调用全局 delete } }; int main() { Test* p1 = new Test(); delete p1; return 0; } ``` 在这个例子中,`operator new`和`operator delete`分别通过调用全局的`new`和`delete`操作符来分配和释放内存[^1]。此外,它们还输出了调试信息,以便跟踪内存分配和释放的过程。 #### 数组版本的`new[]`和`delete[]` 除了单个对象的`new`和`delete`,还可以重载用于数组的`new[]`和`delete[]`运算符。这允许开发者处理连续内存块的分配与释放,并确保正确调用所有元素的构造函数和析构函数。 系统提供的`new[]`和`delete[]`函数原型如下: ```cpp void* __CRTDECL operator new[](size_t _Size); void __CRTDECL operator delete[](void* _Block) noexcept; ``` 如果类中没有显式定义这些函数,则会使用全局版本。因此,在某些情况下,为了保持一致性或提供额外功能(如对齐内存分配),可能需要为自定义类专门重载这些操作符[^3]。 #### 对象池技术中的`new`和`delete`重载 对象池是一种常见的优化手段,它通过预先创建并维护一组对象来减少频繁创建和销毁对象带来的开销。在这种模式下,重载`new`和`delete`可以帮助将对象从池中取出以及归还到池中,从而避免重复实例化高成本的对象[^4]。 例如,一个简单的对象池可以基于链表结构实现,其中`new`操作符从池中获取空闲对象,而`delete`操作符则将对象返回给池。这样不仅减少了动态内存分配的需求,也加快了程序执行速度。 #### 注意事项 - 当重载`new`时,必须确保其返回正确的指针类型,并且能够处理零大小请求(尽管通常不建议这样做)。 - `delete`应在释放内存之前检查传入的指针是否为空。 - 如果重载了`new`但未同时重载`delete`,那么可能会出现行为不一致的问题,比如使用默认的`delete`去释放由自定义`new`分配的内存,这可能导致错误甚至崩溃。 - 使用`new`表达式时,编译器会在分配完内存后自动调用构造函数;同样地,`delete`表达式会先调用析构函数再释放内存。因此,当自定义这两个操作符时,应保留这一语义不变。 总之,合理利用`new`和`delete`的重载能力可以让程序员更好地掌控底层资源管理,进而提升应用程序的整体表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值