new文件用来管理c++的动态内存,这个文件声明了几个全局空间的函数(不是std空间的函数,全局空间的函数调用时是用全局作用域解析符),包括operator new 和operator delete的重载 ,这些函数用于处理动态存储空间请求。
其new的头文件源代码
#ifndef _NEW #define _NEW #include <cstddef> #include <exception> extern "C++" { namespace std { //注意此空间内函数或者变量处于std空间,使用时需要添加std::调用 /** * 当内存分配错误的时候抛出bad_alloc异常 */ class bad_alloc : public exception { public: bad_alloc() throw() { } virtual ~bad_alloc() throw(); }; //当内存分配失败时用此结构体替代异常,使用嵌入式环境,嵌入式环境没有异常功能 struct nothrow_t { }; extern const nothrow_t nothrow; ///当内存分配失败时,调用new_handler ///new_handler试着去分配更多得存储空间,当且仅当申请内存成功时,才会返 ///否则抛出bad_alloc异常或者终止程序(调用abort或者exit) typedef void (*new_handler)(); new_handler set_new_handler(new_handler) throw(); } // namespace std //全局空间函数,调用时加上作用域解析符,如::operator new () void* operator new(std::size_t) throw (std::bad_alloc); void* operator new[](std::size_t) throw (std::bad_alloc); void operator delete(void*) throw(); void operator delete[](void*) throw(); void* operator new(std::size_t, const std::nothrow_t&) throw(); void* operator new[](std::size_t, const std::nothrow_t&) throw(); void operator delete(void*, const std::nothrow_t&) throw(); void operator delete[](void*, const std::nothrow_t&) throw(); //placement operator new/delete inline void* operator new(std::size_t, void* __p) throw() { return __p; } inline void* operator new[](std::size_t, void* __p) throw() { return __p; } inline void operator delete (void*, void*) throw() { } inline void operator delete[](void*, void*) throw() { } } // extern "C++" #endif
1、关于new operator与operator new
operator new() 仅仅分配内存空间,是对malloc的一个封装,返回的是一个void *,如
int* a = (int *)::operator new(sizeof(int));
只是对a分配了空间,通过vs2012进行调试你会发现operator new 的实现如下:其主要是调用malloc(size),而没有对内存进行初始化
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) { // try to allocate size bytes void *p; while ((p = malloc(size)) == 0) if (_callnewh(size) == 0) { // report no memory static const std::bad_alloc nomem; _RAISE(nomem); } return (p); }
对于new operator先调用operator new分配内存空间,然后调用构造函数初始化
#include <iostream> using namespace std; class Foo{ public: Foo(){ cout<<"Foo constructor"<<endl; a = 10; } //对operator new进行重写 void* operator new(size_t size){ cout<<"Foo operator new"<<endl; return ::operator new(size); } int a; }; int main(){ Foo* f1 =(Foo *) ::operator new(sizeof(Foo)); cout<<f1->a<<endl; Foo* f2 = new Foo(); cout<<f2->a<<endl; } /*************** 结果为: 3420040 Foo operator new Foo constructor 10 *****************/
由于operator new 只是分配空间未调用构造函数,所以公有变量未初始化,是个随机值,
而new Foo() 先调用operator new 然后再构造函数,所以会先出现Foo operator new
2、关于placement new(定位放置new)
placement new 是operator new的一个重载的版本,如果你想在已经分配的内存中创建一个对象,这时不能使用new。而placement new永许你在一个已经分配好的内存中(栈或者堆中)构造一个新的对象,原型中void* p实际就是指向一个已经分配好的内存缓冲区的首地址。c++支持placement operator new,能够在预先分配的缓冲区中构造对象,避免new内存分配时查找内存和分配内存的时间,而且由于内存已经分配,没有内存分配失败的危险,在内存池,垃圾回收器,和性能或异常安全可以使用
char *buf = new char[sizeof(string)]; // pre-allocated buffer string *p = new (buf) string("hi"); // placement new
char memory[sizeof(Foo)]; void* place = memory; Foo* f = new(place) Foo();
3、关于set_new_handler
new_handler类型的函数是默认内存申请函数(operator new和operator new[])申请内存失败,会被调用。
new_handler函数会试图为新的内存申请请求提供更多的可用空间。当且仅当,函数成功地提供了更多的可用空间,它才返回。
否则,要么抛出bad_alloc异常(或bad_alloc派生类)要么终止程序(比如调用abort或exit)。
如果new_handler函数返回(即,它提供了更多可用空间)后,当内存申请函数申请指定的内存空间失败时,它会被再次调用,或直到new_handle函数不返回或被替换。
#include <iostream> #include <new> char* memoryPool = NULL; void my_new_handler(){ if(NULL != memoryPool){ // 删除一些不用的内存 delete[] memoryPool; memoryPool = NULL; }else{ //没有足够的内存 throw std::bad_alloc(); } return ; } int main(){ std::set_new_handler(my_new_handler); memoryPool = new char[512*1024*1024]; if(memoryPool == NULL){ std::cout<<"allocator fail"<<std::endl; return -1; } char *p = NULL; for(int i = 0 ; i < 4; ++ i){ p = new char[256*1024*1024]; std::cout<<i+1<<" allocator 512M "<<p<<std::endl; } return 0; }