C++有关new/delete的头文件之一 是标准库, operator new/delete可以参考; new/delete 和operator new/delete是存在相当大的差别的.在VS2005上测试下列代码:
-
#include
-
#include
-
#include
-
using namespace std;
-
-
//#define NEW_ARRAY
-
//#define NEW_OPRATOR
-
//#define NEW_FAIL_OPERATOR
-
//#define NEW_HANDLER
-
-
-
#if defined(NEW_HANDLER)
-
void my_handler()
-
{
-
cout <<"void my_handler() called"<
-
throw bad_alloc();
-
}
-
#endif//NEW_HANDLER
-
-
struct myclass
-
{
-
myclass()
-
{
-
cout <<"myclass constructed\\n";
-
}
-
-
~myclass()
-
{
-
cout <<"myclass deconstructed\\n";
-
}
-
-
virtual void testmyclass()
-
{
-
cout <<"myclass testmyclass called\\n";
-
}
-
};
-
-
class base
-
{
-
public:
-
base()
-
{
-
cout <<"base constructed sizeof(*this)="<
-
}
-
-
virtual ~base()
-
{
-
cout <<"base deconstructed\\n";
-
}
-
};
-
-
class superClass : public base
-
{
-
public:
-
superClass()
-
{
-
cout <<"superClass constructed sizeof(*this)="<
-
#if defined(NEW_FAIL_OPERATOR)
-
throw bad_alloc();
-
#endif//NEW_FAIL_OPERATOR
-
-
#if defined(NEW_HANDLER)
-
#define BIG_SIZE 0x7fffffff
-
new char[BIG_SIZE];
-
#endif//NEW_HANDLER
-
}
-
-
superClass(int a)
-
{
-
cout <<"superClass constructed a="<
-
}
-
-
~superClass()
-
{
-
cout <<"superClass deconstructed\\n";
-
}
-
-
void* operator new (std::size_t s) throw (std::bad_alloc)
-
{
-
void *p = malloc(s);
-
cout <<"operator new(size_t s) called ; s="<
-
return p;
-
}
-
-
void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw()
-
{
-
void *p = malloc(s);
-
cout <<"void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw(); s="<
-
return p;
-
}
-
-
void * operator new(size_t, void *_Where) throw()
-
{
-
try
-
{
-
cout <<"operator new(size_t, void *_Where) called; strlen(_Where)="<
-
return (_Where);
-
}
-
catch (...)
-
{
-
-
}
-
// construct array with placement at _Where
-
cout <<"operator new(size_t, void *_Where) called; strlen(_Where)="<
-
return (_Where);
-
}
-
-
void* operator new[](size_t s) throw()
-
{
-
void *p = malloc(s);
-
cout <<"void* operator new[](size_t count) throw(std::bad_alloc) called; s="<
-
return p;
-
}
-
-
void* operator new[](size_t s, const std::nothrow_t&) throw()
-
{
-
void *p = malloc(s);
-
cout <<"void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s="<
-
return p;
-
}
-
-
void* operator new[](size_t s, void* object) throw()
-
{
-
try // has been constructed before current
-
{
-
cout <<"void* operator new[](size_t s, void* object) throw() called; s="<
-
return (object);
-
}
-
catch (...)
-
{
-
}
-
-
cout <<"void* operator new[](size_t s, void* object) throw() called; s="<
-
return object;
-
}
-
-
void operator delete (void* _Where) throw ()
-
{ // construct array with placement at _Where
-
cout <<"void operator delete (void* _Where) throw () called; strlen(_Where)="<
-
free(_Where);
-
return ;
-
}
-
-
void operator delete (void* p, const std::nothrow_t& nothrow_constant) throw()
-
{
-
cout <<"void operator delete (void* p, const std::nothrow_t& nothrow_constant) throw() called; strlen(p)="<
-
free(p);
-
return ;
-
}
-
-
void operator delete (void* ptr, void* voidptr2) throw()
-
{
-
cout <<"void operator delete (void* ptr, void* voidptr2) called; strlen(ptr)="<
-
return ;
-
}
-
-
void operator delete[] (void* p) throw ()
-
{
-
cout <<"void operator delete[] (void* ptr) throw ()) called; strlen(p)="<
-
free(p);
-
return ;
-
}
-
-
void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw()
-
{
-
cout <<"void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw() called \\n";
-
free(p);
-
return ;
-
}
-
-
void operator delete[] (void* ptr, void* voidptr2) throw()
-
{
-
cout <<"void operator delete[] (void* ptr, void* voidptr2) throw() called; strlen(ptr)="<
-
return ;
-
}
-
};
-
-
-
int main(int argc, char* argv[])
-
{
-
#if defined(NEW_HANDLER)
-
new_handler old_handler = set_new_handler(my_handler);
-
superClass * pHandlerMem = NULL;
-
try
-
{
-
pHandlerMem = new superClass;
-
}
-
catch (...)
-
{
-
cout <<"pHandlerMem = new superClass; exception"<
-
}
-
-
#endif//
-
-
#if defined(NEW_ARRAY)
-
// uses first version:
-
int * pa1 = new int[5];
-
-
// uses second version:
-
int * pa2 = new (nothrow) int[4];
-
-
// uses third version:
-
//pair pa3 = get_temporary_buffer(3);
-
//new (pa3.first) myclass[3]; // calls constructors
-
//return_temporary_buffer(pa3.first);// cut from %20new[]/
-
-
int superClassSize = sizeof(superClass);
-
superClass *paBase = NULL;
-
superClass *pArryCon = NULL;
-
try
-
{
-
cout <<"paBase = (superClass *) operator new[](2 * superClassSize);"<
-
paBase = (superClass *) operator new[](2 * superClassSize);
-
pArryCon = new (paBase) superClass[2];
-
delete pArryCon;
-
paBase = NULL;
-
-
cout <<"paBase = new superClass[2];"<
-
paBase = new superClass[2];
-
delete paBase;
-
paBase = NULL;
-
-
cout <
-
paBase = (superClass *)superClass::operator new[](2 * superClassSize);
-
superClass::operator delete[](paBase, (void*)paBase);
-
paBase = NULL;
-
-
cout <<"paBase = (superClass *) new (nothrow) const superClass[2];"<
-
paBase = (superClass *) new (nothrow) const superClass[2];
-
delete paBase;
-
paBase = NULL;
-
-
//paBase = new superClass[2];
-
//paBase = (superClass *)superClass::operator new[](paBase);
-
//superClass::operator delete[](paBase, (void*)paBase);
-
//throw;
-
}
-
catch (...)
-
{
-
cout <<"catch (...)"<
-
//delete [] paBase;
-
return 0;
-
}
-
//superClass *paBase = new superClass[5];
-
//delete[](paBase);
-
//superClass *paBase = (superClass *)superClass::operator new[](20);
-
//superClass::operator delete[](paBase);
-
-
//superClass *paOpBase = operator new[](sizeof(superClass));
-
#endif//NEW_ARRAY
-
-
#if defined(NEW_OPRATOR)
-
cout <<"superClass *pBase = new (nothrow) superClass;"<
-
superClass *pBase = new (nothrow) superClass;
-
delete pBase ;
-
-
cout <<"pBase = (superClass *)superClass::operator new (sizeof(superClass));"<
-
pBase = (superClass *)superClass::operator new (sizeof(superClass));
-
superClass * pPlace = new (pBase) superClass;
-
// delete pBase;
-
pPlace->~superClass();
-
superClass::operator delete(pBase);
-
-
//new (pBase) superClass;
-
cout <<"const superClass *pBase3 = new const superClass();"<
-
const superClass *pBase3 = new const superClass();
-
delete pBase3;
-
-
cout <<"size_t s = sizeof(superClass);"<
-
size_t s = sizeof(superClass);
-
superClass *pBase2 = (superClass *)operator new (s);
-
superClass * pBase5 = new (pBase2) superClass(1);
-
pBase5->~superClass();
-
operator delete(pBase5);
-
//delete pBase5;
-
-
cout <<"pBase2 = (superClass *)new superClass;"<
-
pBase2 = (superClass *)new superClass;
-
new (pBase2) superClass;
-
pBase2->~superClass();
-
operator delete(pBase2);
-
-
int * p1 = new int;
-
// same as:
-
// int * p1 = (int*) operator new (sizeof(int));
-
-
int * p2 = new (nothrow) int;
-
// same as:
-
// int * p2 = (int*) operator new (sizeof(int),nothrow);
-
-
myclass * p3 = (myclass*) operator new (sizeof(myclass));
-
// (!) not the same as:
-
// myclass * p3 = new myclass;
-
// (constructor not called by function call, even for non-POD types)
-
-
p3->testmyclass();
-
-
new (p3) myclass; // calls constructor
-
// same as:
-
// operator new (sizeof(myclass),p3)
-
-
//delete p3;
-
operator delete(p3);
-
-
int delay = 1;
-
myclass *p4 = new myclass;
-
delete p4;
-
p4 = NULL;
-
#endif //NEW_OPRATOR
-
-
return 0;
-
}
根据如上代码,我们通过控制宏进行如下情况分析:
一. 对象内部因为申请大内存异常情况. new内存申请, 在对象内部申请大内存,因内存不足的情况, 只打开宏NEW_HANDLER编译运行输出为:
-
operator new(size_t s) called ; s=4
-
base constructed sizeof(*this)=4
-
superClass constructed sizeof(*this)=4
-
void my_handler() called
-
base deconstructed
-
void operator delete (void* _Where) throw () called; strlen(_Where)=3
-
pHandlerMem = new superClass; exception
根据输出结果, new对象时先申请内存, 在调用对象的构造函数, 有继承体系的根据继承体系进行调用; 当对象因为申请内存失败没有成功创建, 先调用内存失败处理函数my_handler(), 在内存失败处理函数中在抛出异常, 就再调用创建好的对象的释构函数, 最后在调用相应operator delete进行内存释放, 防止内存泄漏. (但是strlen(_Where) = 3的原因未知.嗨???), 用new进行其他方式进行superClass内存操作情况相似(new, operator new, superClass::operator new 加上放置式).
二. new申请对象内存,对象内部抛出异常。 只同时打开宏NEW_FAIL_OPERATOR和NEW_HANDLER, 当用new对象申请对象内存, 对象throw throw bad_alloc(), 将不调用内存失败处理函数my_handler(), 而是直接调用创建好的对象释构函数, 然后调用相应的operator delete进行内在释放. new, new const 和new的放置式调用失败后, 调用的是不同的operator delete. 输出结果为:
-
operator new(size_t s) called ; s=4
-
base constructed sizeof(*this)=4
-
superClass constructed sizeof(*this)=4
-
base deconstructed
-
void operator delete (void* _Where) throw () called; strlen(_Where)=3
-
pHandlerMem = new superClass; exception
三. operator new/delete配对情况. 只打开示例程序宏NEW_OPRATOR,编译运行输出:
-
base deconstructed
-
void operator delete (void* _Where) throw () called; strlen(_Where)=3
-
const superClass *pBase3 = new const superClass();
-
operator new(size_t s) called ; s=4
-
base constructed sizeof(*this)=4
-
superClass constructed sizeof(*this)=4
-
superClass deconstructed
-
base deconstructed
-
void operator delete (void* _Where) throw () called; strlen(_Where)=3
-
size_t s = sizeof(superClass);
-
operator new(size_t, void *_Where) called; strlen(_Where)=9
-
base constructed sizeof(*this)=4
-
superClass constructed a=1
-
superClass deconstructed
-
base deconstructed
-
pBase2 = (superClass *)new superClass;
-
operator new(size_t s) called ; s=4
-
base constructed sizeof(*this)=4
-
superClass constructed sizeof(*this)=4
-
operator new(size_t, void *_Where) called; strlen(_Where)=3
-
base constructed sizeof(*this)=4
-
superClass constructed sizeof(*this)=4
-
superClass deconstructed
-
base deconstructed
并在 p3->testmyclass();这一行发生异常。 对着结果分析。
(1)首先,new (nothrow) superClass 对应void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw();此时delete 对应 void operator delete (void* _Where) throw (). 对着superClass *pBase = new (nothrow) superClass; 这行产生void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw()的调用,然后调用对象的构造函数。 当执行delete pBase ;先调用对象的析构函数, 然后调用 void operator delete (void* _Where) throw ();
(2) superClass::operator new (sizeof(superClass))对应superClass类中void* operator new (std::size_t s) throw (std::bad_alloc),但是不会调用对象的构造函数,相当于内存分配。 语句new (pBase) superClass并不会分配内存,但它会引起superClass构造函数的调用,对就superClass类中void * operator new(size_t, void *_Where) throw()。 语句pPlace->~superClass();只是调用pPlace所指的对象上调用~superClass这个析构函数,对象本身的内存没有释放,把pPlace->~superClass()当成类似其他成员函数的调用。 语句superClass::operator delete(pBase)对应superClass类中void operator delete (void* _Where) throw ()函数,这种调用不会引起对象析构函数的调用.
-
pBase = (superClass *)superClass::operator new (sizeof(superClass));//调用void* operator new (std::size_t s) throw (std::bad_alloc),
-
-
superClass * pPlace = new (pBase) superClass;//调用void * operator new(size_t, void *_Where) throw()和对象构造函数
-
-
// delete pBase;
-
-
pPlace->~superClass();//调用~superClass()和virtual ~base()两个对象析构函数,如果virtual ~base()为~base(),则只调用~superClass()函数
-
-
superClass::operator delete(pBase);//只调用superClass类中void operator delete (void* _Where) throw (), 不引起对象析构函数调用
(3)语句new const superClass()对应superClass类中void* operator new (std::size_t s) throw (std::bad_alloc),并调用对象构造函数。相应的delete 对应superClass类中void operator delete (void* _Where) throw (),并调用相应的析构函数.
-
const superClass *pBase3 = new const superClass();//调用void* operator new (std::size_t s) throw (std::bad_alloc)和对象构造函数
-
delete pBase3;//调用void operator delete (void* _Where) throw ()和对象析构函数
(4) 语句(superClass *)operator new (s)对应库函数void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc),不调用对象构造函数。语句new (pBase2) superClass(1)对应superClass类中void * operator new(size_t, void *_Where) throw(), 这个称为new 的放置式,此时不会给对象分配内存,而是产生对象superClass(1)构造函数的调用,在相应指定的内存上构造对象。语句pBase5->~superClass()对应调用对象的析构函数。语句operator delete(pBase5)对应库函数void operator delete(void *pUserData), 同时不产生对象的析构函数调用.
-
size_t s = sizeof(superClass);
-
superClass *pBase2 = (superClass *)operator new (s);//库函数void *__CRTDECL operator new(size_t size),不产生构造函数调用
-
superClass * pBase5 = new (pBase2) superClass(1);//调用superClass类void * operator new(size_t, void *_Where) throw(),产生superClass(1)和base()调用
-
pBase5->~superClass();//调用~superClass()和virtual ~base()
-
operator delete(pBase5);//调用库函数void operator delete(void *pUserData), 不产生析构函数调用
(5) 语句new superClass 对应superClass类void* operator new (std::size_t s) throw (std::bad_alloc),并产生对象构造函数调用。
语句new (pBase2) superClass对应superClass类中void * operator new(size_t, void *_Where) throw(),不产生内存分配,但引起对象构造函数的调用, new superClass和new (pBase2) superClass共引起两上对象构造函数调用,相当的危险。pBase2->~superClass();
对应调用对象析构函数,但是对象内存没有释放。operator delete(pBase2)释放对象内存,但是不产生对象构造函数的调用。虽然pBase2->~superClass()和operator delete(pBase2)组合功能类似delete对象,但是和delete并不相同,特别是superClass::operator delete(pBase2)调用是允许的.
-
pBase2 = (superClass *)new superClass;//调用superClass类void* operator new (std::size_t s) throw (std::bad_alloc)和构造函数
-
new (pBase2) superClass;//调用superClass类void * operator new(size_t, void *_Where) throw()和构造函数。
-
pBase2->~superClass();//对象析构函数
-
operator delete(pBase2);//库函数void operator delete( void * p )
(6) 分析在 p3->testmyclass()这一行发生异常原因。对于类
-
struct myclass
-
{
-
myclass()
-
{
-
cout <<"myclass constructed\\n";
-
}
-
-
~myclass()
-
{
-
cout <<"myclass deconstructed\\n";
-
}
-
-
virtual void testmyclass()
-
{
-
cout <<"myclass testmyclass called\\n";
-
}
-
};
其中virtual void testmyclass() 说明testmyclass是虚的,语句myclass * p3 = (myclass*) operator new (sizeof(myclass))只是分配内存,并没有把对象构造起来,也就是说对象虚表不存在,调用p3->testmyclass()肯定要异常。如果写成如下,即在调用p3->testmyclass()前先调用把new (p3) myclass对象构造起来,就可以成功调用。(注:如果virtual void testmyclass()改成 void testmyclass()就可以运行通过,不抛出异常,反汇编下就知道了. 又一个C++特性)
-
superClass *pBase = new (nothrow) superClass;
-
void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw(); s=4
-
base constructed sizeof(*this)=4
-
superClass constructed sizeof(*this)=4
-
superClass deconstructed
-
base deconstructed
-
void operator delete (void* _Where) throw () called; strlen(_Where)=3
-
pBase = (superClass *)superClass::operator new (sizeof(superClass));
-
operator new(size_t s) called ; s=4
-
operator new(size_t, void *_Where) called; strlen(_Where)=9
-
base constructed sizeof(*this)=4
-
superClass constructed sizeof(*this)=4
-
superClass deconstructed
-
myclass * p3 = (myclass*) operator new (sizeof(myclass));
-
// (!) not the same as:
-
// myclass * p3 = new myclass;
-
// (constructor not called by function call, even for non-POD types)
-
-
//p3->testmyclass();
-
-
new (p3) myclass; // calls constructor
-
p3->testmyclass();
-
// same as:
-
// operator new (sizeof(myclass),p3)
-
-
//delete p3;
-
operator delete(p3);
输出如下:
-
myclass constructed
-
myclass testmyclass called
-
myclass constructed
用operator delete(p3)代替delete p3有可能产生内存泄漏, 因为operator delete()会造成对象析构函数无法被调用.
还有其他的new/delete operator new/operator delete组合方法, 我们看出来operator new/delete在用户调用时,相当于函数调用, 当编译器调用时,就会产生构造或者析构操作. 同时使用new方式的不同,会在异常或者delete后造成不同调用.
阅读(1055) | 评论(0) | 转发(0) |