1. 测试代码:
#include <iostream>
#include <new>
#include <cstring>
#include <cstdlib>
using namespace std;void* operator new(size_t size)
{cout << "global Override operator new" << endl;if (void* ptr = malloc(size)) return ptr;elsethrow bad_alloc();
}void* operator new(size_t size, int flag)
{cout << "global Override operator new: " << flag << endl;return (::operator new(size));
}void operator delete (void* ptr)
{cout << "global Override operator delete" << endl;free(ptr);ptr = nullptr;
}void operator delete (void* ptr, int flag)
{cout << "Override operator delete: " << flag << endl;::operator delete(ptr);ptr = nullptr;
}int main()
{int* ptr = new int(10);delete ptr;cout << endl << "------------" << endl << endl;ptr = new(20) int(10);delete ptr;return 0;
}
输出结果:
分析:
从上面的结果可以看出,new int(10);直接先调用 operator new(size_t size); 由于int没有构造函数,在那块内存上调用int的构造函数; 在delete ptr; 的时间直接调用 operator delete(void * ptr);这个函数
当
new(20) int(10);
的时候,则调用重载版本的 operator new(size_t size, int flag); 而该函数有调用了 operator new(size_t size); 函数,释放的时候delete ptr;还是直接只调用operator delete(void * ptr);(注:这里初步提出为啥不调用operator delete(void * ptr, int flag); 这个函数来释放ptr ???因为它的用途不在这,而在于下面将要讲的。
2. 测试代码:
#include <iostream>
#include <new>
#include <cstring>
#include <cstdlib>
using namespace std;void* operator new(size_t size)
{cout << "global Override operator new" << endl;void* ptr = malloc(size);return ptr;
}void* operator new(size_t size, int flag)
{cout << "global Override operator new: " << flag << endl;return (::operator new(size));
}void operator delete (void* ptr)
{cout << "global Override operator delete" << endl;free(ptr);ptr = nullptr;
}void operator delete (void* ptr, int flag)
{cout << "Override operator delete: " << flag << endl;::operator delete(ptr);ptr = nullptr;
}class Base
{
public:Base(){cout << "Base construct" << endl;throw 2;}~Base(){cout << "Base destructor" << endl;}//类中定制的operator new会覆盖全局的函数,但可以通过简单的调用全局的函数来实现调用static void* operator new(size_t size){cout << "operator new of Base" << endl;return ::operator new(size); //调用全局的operator new}static void* operator new(size_t size, int flag){cout << "Override operator new of Base: " << flag << endl;return operator new(size);}static void operator delete(void* ptr){cout << "Operator delete of Base" << endl;::operator delete(ptr);}static void operator delete(void* ptr, int flag){cout << "Override operator delete of Base: " << flag << endl;operator delete(ptr);}int x;int y;
};
int main()
{try{Base* bptr = new(20) Base;}catch (...){cout << "catch a exception" << endl;}return 0;
}
输出结果:
2. 若是不给Base类重载 static void operator delete(void * ptr, int flag);
这个函数,结果则如下图:
#include <iostream>
#include <new>
#include <cstring>
#include <cstdlib>
using namespace std;void* operator new(size_t size)
{cout << "global Override operator new" << endl;void* ptr = malloc(size);return ptr;
}void* operator new(size_t size, int flag)
{cout << "global Override operator new: " << flag << endl;return (::operator new(size));
}void operator delete (void* ptr)
{cout << "global Override operator delete" << endl;free(ptr);ptr = nullptr;
}void operator delete (void* ptr, int flag)
{cout << "Override operator delete: " << flag << endl;::operator delete(ptr);ptr = nullptr;
}class Base
{
public:Base(){cout << "Base construct" << endl;throw 2;}~Base(){cout << "Base destructor" << endl;}//类中定制的operator new会覆盖全局的函数,但可以通过简单的调用全局的函数来实现调用static void* operator new(size_t size){cout << "operator new of Base" << endl;return ::operator new(size); //调用全局的operator new}static void* operator new(size_t size, int flag){cout << "Override operator new of Base: " << flag << endl;return operator new(size);}static void operator delete(void* ptr){cout << "Operator delete of Base" << endl;::operator delete(ptr);}int x;int y;
};
int main()
{try{Base* bptr = new(20) Base;}catch (...){cout << "catch a exception" << endl;}return 0;
}
输出结果:
二、定位new表达式
operator new和operator delete和alloctor类的allocate和deallocate很像,都是负责分配和释放内存的函数,但是对于operator new分配的内存空间我们无法使用construct函数构造对象,我们应该使用new的定位new形式构造对象。
1. 测试代码:
#include <iostream>
#include <new>
using namespace std;const int chunk = 16;
class Foo
{
public:int val() { return _val; }Foo() { _val = 0; }
private:int _val;
};//预分配内存,但没有Foo对象
char* buf = new char[sizeof(Foo) * chunk];
int main(void)
{//在buf中创建一个Foo对象Foo* pb = new (buf) Foo;//检查一个对象是否被放在buf中if (pb->val() == 0){cout << "new expressio worked!" << endl;}//到这里不能再使用pbdelete[] buf;return 0;
}
placement new的作用就是:创建对象但是不分配内存,而是在已有的内存块上面创建对象。用于需要反复 创建并删除的对象上,可以降低分配释放内存的性能消耗。定位new表达式(placement new expression),允许程序员将对象创建在已经被分配好的内存中,new表的式的形式如下:
new (place_address) type
new (palce_address) type (initializer-list)
【Note】:
- 当只传入一个指针类型的实参时,定位new表达式构造对象但是不分配内存,这个指针没有要求,甚至可能是一个不是一个指向动态内存的指针
- 调用析构函数会销毁对象,但是不会释放内存。
2. 测试代码:
#include <iostream>
using namespace std;
char addr1[100];
int main()
{cout << "******定位new表达式演示***by David***" << endl;char addr2[100];char *addr3 = new char[100];cout << "addr1 = " << (void*)addr1 << endl;cout << "addr2 = " << (void*)addr2 << endl;cout << "addr3 = " << (void*)addr3 << endl;int *p = nullptr;p = new(addr1)int; 把内存分配到静态区*p = 1;cout << (void*)p << " " << *p << endl;p = new(addr2)int; 把内存分配到栈区*p = 2;cout << (void*)p << " " << *p << endl;p = new(addr3)int; //把内存分配到堆区*p = 3;cout << (void*)p << " " << *p << endl;return 0;
}
输出结果:
参考资料
- 定制自己的new和delete:operator new 和 operator delete
- 特殊的工具和技术