operator new是一组函数,当使用new operator申请内存并调用构造函数时会用到它,operator new函数就是用来申请内存的,差不多相当于malloc.
operator delete也是一组函数,如果new operator调用operator new分配空间后,调用构造函数失败,则operator delete被C++运行环境调用来释放operator new申请到的空间,程序员不会手动直接调用这类函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | namespace std { class bad_alloc; class bad_array_new_length; struct nothrow_t {}; extern const nothrow_t nothrow; typedef void (*new_handler)(); new_handler get_new_handler() noexcept; new_handler set_new_handler(new_handler new_p) noexcept; } void* operator new(std::size_t size); void* operator new(std::size_t size, const std::nothrow_t&) noexcept; void operator delete(void* ptr) noexcept; void operator delete(void* ptr, const std::nothrow_t&) noexcept; void* operator new[](std::size_t size); void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; void operator delete[](void* ptr) noexcept; void operator delete[](void* ptr, const std::nothrow_t&) noexcept; void* operator new (std::size_t size, void* ptr) noexcept; void* operator new[](std::size_t size, void* ptr) noexcept; void operator delete (void* ptr, void*) noexcept; void operator delete[](void* ptr, void*) noexcept; |
上面一组东西是C++标准规定的。
在namespace std中,定义了bad_alloc,nothrow_t,以及new_handler类型和set_new_handler函数。
第10、11行:
1 2 | void* operator new(std::size_t size); void* operator new(std::size_t size, const std::nothrow_t&) noexcept; |
它用来分配size字节的空间。第一种形式如果分配空间失败,则抛出bad_alloc;第二种形式,如果分配失败了,则返回NULL,不抛出bad_alloc.
1 2 | void operator delete(void* ptr) noexcept; void operator delete(void* ptr, const std::nothrow_t&) noexcept; |
上面两种operator delete,分别对应第11、12行两种operator new。
1 2 | void* operator new[](std::size_t size); void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; |
上面两种operator new[],用来为数组分配空间,它们的区别与第11、12行的operator new的区别类似。
1 2 | void* operator new (std::size_t size, void* ptr) noexcept; void* operator new[](std::size_t size, void* ptr) noexcept; |
上面两种,是最普通的placement new,它们仅仅返回ptr,不做其它事情。
1 2 | void operator delete (void* ptr, void*) noexcept; void operator delete[](void* ptr, void*) noexcept; |
上面两种placement delete,什么都不做,只是与placement new对应,很诡异。
分配程序,使用VS2010,
1 2 3 4 5 6 7 | int _tmain(int argc, _TCHAR* argv[]) { int *p = new int; *p = 0; delete p; return 0; } |
单步跟踪会发现new调用了下面的operator new
1 2 3 4 5 6 7 8 9 10 11 12 | 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); } |
可以看出来,这个版本的operator new调用了malloc分配空间,如果分配成功,则返回指向分配的空间的指针,如果分配失败,且_callnewh(size)返回0,则抛出异常。对于上面的例子,不会失败。
再构造一个分配内存失败的例子,我们可以看到_callnewh()被调用:
1 2 3 4 5 6 7 | int _tmain(int argc, _TCHAR* argv[]) { for(;;) int *p = new int[1024*1024*255]; return 0; } |
还是单步运行,在第二次new的时候,malloc失败,调用了_callnewh()。
1 2 3 4 5 6 7 8 9 10 11 12 | /* pointer to old-style C++ new handler */ _PNH _pnhHeap; extern "C" int __cdecl _callnewh(size_t size) { { _PNH pnh = (_PNH) DecodePointer(_pnhHeap); if ( (pnh == NULL) || ((*pnh)(size) == 0) ) return 0; } return 1; } |
_callnewh的函数体如上:如果new_handler是NULL或者(*pnh)(size) == 0则返回0。我不懂第二个表达式的意思。这次运行我观察到new_handler为NULL,直接就返回0了,然后抛出了异常。
