在内存管理中,::operator new()/::operator delete() 、delete/new、 placement new 是不同的:
::operator new():只是进行空间的申请而不调用构造函数,可以理解为只是对 malloc
的简单封装,返回 void*
。可以进行类内重载或者全局重载,类内没有重载则寻找全局new。
::operator delete():类似,只是对空间进行释放,而不调用析构函数,可以理解为是对 free
的简单封装。可以类内重载或者全局重载,类内没有重载则寻找全局delete。
new:分为三个步骤:
- 调用 ::operator new(sizeof(type)) 申请空间(首先查找类内的 ::operator new() )
- 调用 type->constructor 对申请的对象进行构造
- 返回对应的指针类型 type*
delete:同new,分为三个步骤:
- 调用对应的 type->destroy 进行析构(首先查找类内的 ::operator new() )
- 调用 ::operator delete(type*) 进行空间释放
- return
//类内重载new、delete#includeclass test {public:void* operator new(size_t n) {std::cout << "分配了" << n << "bytes" << std::endl;return malloc(n);}void operator delete(void* ptr) {std::cout << "释放内存" << std::endl;free(ptr);}test() {std::cout << "constructor" << std::endl;}void sayHello() {std::cout << text << std::endl;}~test() {std::cout << "destroy" << std::endl;}private:std::string text = "hello world";};templatevoid constructor(T1* ptr, const T2& value) {new(ptr)T1(value);}int main() {test* t2 = new test();delete t2;}
//全局重载new、deletevoid* operator new(size_t n) {std::cout << "分配" << n << "个bytes" << std::endl;return malloc(n);}void operator delete(void* p) {free(p);}#includeclass test {public:test() {std::cout << "constructor" << std::endl;}void sayHello() {std::cout << text << std::endl;}~test() {std::cout << "destroy" <sayHello();//未初始化,打印失败t1->test::test();t1->sayHello();t1->~test();::operator delete(t1);}
placement new:布局new,比较特殊的一种new,用于在已分配的内存上创建对象,不申请另外的空间,但是需要手动调用析构函数。在内存池中就可以看到对于 placement new 的使用了。
使用placement new的例子:
#includeclass test {public:test() {std::cout << "constructor" << std::endl;}void sayHello() {std::cout << text << std::endl;}~test() {std::cout << "destroy" << std::endl;}private:std::string text = "hello world";};templatevoid constructor(T1* ptr, const T2& value) {new(ptr)T1(value);}int main() {char* buf = (char*)::operator new(sizeof(test) * 2);std::cout << (void*)buf <sayHello();//未初始化buf,打印出现问题constructor((test*)buf, test());std::cout << (void*)buf <sayHello();//已初始化,打印hello world((test*)buf)->~test();//手动析构对象delete buf;}
小小总结:
真正申请和释放内存空间其实是在 ::operator new(size_t) 中调用 malloc() 和在 ::operator delete() 中调用 **free() **,构造函数和析构函数并不会申请或释放内存空间。而placement new不调用malloc,而是在已分配的内存上创建对象。