1、new和delete表达式的工作机理
1)new表达式实际执行了三步
string *sp=new string("aaaa"); string *arr=new string[10];//string采用默认初始化
a、调用一个名为operator new(或者operator new[])的标准库函数,分配一块足够大的、原始的、未命名的内存空间,来准备存储对象或者对象的数组;
b、编译器运行相应的构造函数构造这些对象,在这里运行的是string的构造函数;
c、返回一个指向该对象或者对象数组的指针。
2)delete执行了两步操作:
delete sp; delete []arr;
a、对sp或者arr所指的数组中的元素执行相应的析构函数;
b、编译器调用名为operator delete或者operator delete[]的标准库函数释放内存空间。
所以,想要控制内存分配,需要重载标准库函数中的operator new和operator delete函数,可以在类中重载,也可以在类外(全局)重载;使用作用域运算符::可以忽略类中的函数,直接执行全局作用域中的版本,::operator new,::operator delete。
2、标准库函数中的operator new 和operator delete
#ifndef _NEWANDDELETE_H_ #define _NEWANDDELETE_H_ #include<new> #include<cstdlib> using namespace std; class NewAndDelete { public: /** * 以下是标准库函数中的operate new和operator delete * 前面4个会抛出异常,后面4个不会抛出异常 * 这几个运算符函数是隐式静态的,因为operator new在构造对象之前,用来分配空间;operator delete在对象销毁之后,用来释放空间 * operator new 或者operator new[]的返回类型必须是void*,第一个形参类型必须是size_t并且没有默认实参,size_t代表要分配的空间的大小 * operator delete或者operator delete[]返回类型必须是void,第一个形参类型必须是void*,用指向待释放内存的指针来初始化 * 这两个函数的行为与allocator类中allocate()和deallocate()很类似 */ static void *operator new(size_t); static void *operator new[](size_t); static void operator delete(void*)noexcept; static void operator delete[](void*)noexcept; static void *operator new(size_t, nothrow_t&)noexcept; static void *operator new(size_t, nothrow_t&)noexcept; static void operator delete(void*, nothrow_t&)noexcept; static void operator delete[](void*, nothrow_t&)noexcept; }; //实现示例——使用malloc和free void* NewAndDelete::operator new(size_t size) { if (void *mem = malloc(size)) return mem; else throw bad_alloc();//抛出异常 } void NewAndDelete::operator delete(void *mem)noexcept { free(mem); } void* NewAndDelete::operator new(size_t size, nothrow_t& no)noexcept {//不抛出异常,返回空指针 void *p; if (void *mem = malloc(size)) return mem; else return p; } void NewAndDelete::operator delete(void *mem, nothrow_t& no)noexcept { free(mem); } #endif