new operator的作用:首先会在堆上开辟一段空间(调用的是operator new函数,其实底层实际调用的是malloc),
然后调用new operator后面的typename的构造函数(如果是普通类型则不需要),
最后new operator typename会返回一个指向该堆的内存地址.
如果想要在栈上调用new operator:我们需要做的就是不让new operator调用operator new函数,
而是自己在栈上开辟好一段空间,
然后通过调用placement new (是operator new的重载)将该空间的地址传入.
为方便观察,我们在一个自定义类中重写全局的placement new函数.
#include <iostream>
class NewStackObj
{
public :
NewStackObj(){}
~NewStackObj(){}
static void* operator new(std::size_t size,void *p);
static void operator delete(void *,void *);
};
void* NewStackObj::operator new(std::size_t size,void *p)
{
std::cout << "overwrite placement new" << std::endl;
if(!p)
return ::operator new(size);
return p;
}
void NewStackObj::operator delete(void *,void *)
{
std::cout << "overwrite placement delete" << std::endl;
return;
}
int main()
{
char mem[sizeof(NewStackObj)];
NewStackObj *p = NewStackObj::new(mem) NewStackObj();
}
其中的mem在栈上,且其指向的内存空间也在栈上,内存空间的大小可以放下一个NewStackObj的大小,当执行NewStackObj::new(mem) NewStackObj的时候,调用的是我们自定义的placement new.
全局的placement new的声明和实现如下:
inline _LIBCPP_INLINE_VISIBILITY void* operator new (std::size_t, void* __p) _NOEXCEPT {return __p;}
inline _LIBCPP_INLINE_VISIBILITY void* operator new[](std::size_t, void* __p) _NOEXCEPT {return __p;}
inline _LIBCPP_INLINE_VISIBILITY void operator delete (void*, void*) _NOEXCEPT {}
inline _LIBCPP_INLINE_VISIBILITY void operator delete[](void*, void*) _NOEXCEPT {}
std::size_t size其实就是需要的内存空间的大小,比如我们这里传入的NewStackObj(),它会将NewStackObj对象的大小传入,(如果是基础类型比如int *p = new int,传入的大小是sizeof(int)),然后void*就是我们需要传入的已经开辟好的内存空间的地址,比如我们这里传入的mem.