Posted in 未分类 我抢沙发

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了,然后抛出了异常。

November 6, 2011