分析C++ new[]/delete[]调用与异常, 相比new/delete的调用与异常有相似之处, 但是细节的差别之处更需要注意.以下列出new/delete的标准形式 (来源:%20new/):
-
void* operator new (std::size_t size) throw (std::bad_alloc);
-
-
void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw();
-
-
void* operator new (std::size_t size, void* ptr) throw();
-
-
-
-
void operator delete (void* ptr) throw ();
-
-
void operator delete (void* ptr, const std::nothrow_t& nothrow_constant) throw();
-
-
void operator delete (void* ptr, void* voidptr2) throw();
-
-
-
-
void* operator new[] (std::size_t size) throw (std::bad_alloc);
-
-
void* operator new[] (std::size_t size, const std::nothrow_t& nothrow_constant) throw();
-
-
void* operator new[] (std::size_t size, void* ptr) throw();
-
-
-
-
void operator delete[] (void* ptr) throw ();
-
-
void operator delete[] (void* ptr, const std::nothrow_t& nothrow_constant) throw();
-
-
void operator delete[] (void* ptr, void* voidptr2) throw();
其中new/delete形式,前面的(一)(二)作了部分分析,这里我们使用示例代码情景分析new[]/delete[]. 在示例代码中, 用宏
NEW_FAIL_OPERATOR来控制正常运行版本与异常版本, 当打开宏
NEW_FAIL_OPERATOR时为异常示例版本,关闭宏
NEW_FAIL_OPERATOR为正常运行版本;当为异常版本时,假设构造
函数superClass在第二次构造的时候,抛出异常std::bad_alloc,这样更有利于代码情景分析.
input number输入顺序为:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10, 示例代码如下:
-
#include
-
#include
-
#include
-
using namespace std;
-
-
#define NEW_ARRAY
-
//#define NEW_OPRATOR
-
#define NEW_FAIL_OPERATOR
-
//#define NEW_HANDLER
-
-
static int g_exception = 0;
-
-
struct myclass
-
{
-
myclass()
-
{
-
cout <<"myclass(), myclass constructed\n";
-
#if defined(NEW_FAIL_OPERATOR)
-
throw bad_alloc();
-
#endif//NEW_FAIL_OPERATOR
-
}
-
-
~myclass()
-
{
-
cout <<"~myclass(), myclass deconstructed\n";
-
}
-
-
virtual void testmyclass()
-
{
-
cout <<"myclass testmyclass called\n";
-
}
-
};
-
-
class base
-
{
-
private:
-
int mIndicate;
-
-
public:
-
base()
-
{
-
++g_exception;
-
mIndicate = g_exception;
-
cout <<"base(), base constructed sizeof(*this)="<
-
return (_Where);
-
}
-
catch (...)
-
{
-
-
}
-
// construct array with placement at _Where
-
cout <<"void * operator new(size_t, void *_Where) throw(); 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 ()
-
{
-
try
-
{
-
cout <<"void operator delete[] (void* ptr) throw () called; strlen(p)="<
-
free(p);
-
}
-
catch (...)
-
{
-
cout <<"void operator delete[] (void* ptr) throw () called; exception[unknown]"<
-
}
-
return ;
-
}
-
-
void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw()
-
{
-
try
-
{
-
-
cout <<"void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw() called; strlen(p)="<
-
free(p);
-
}
-
catch (...)
-
{
-
cout <<"void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw() called; exception[unknown]"<
-
}
-
-
return ;
-
}
-
-
void operator delete[] (void* ptr, void* voidptr2) throw()
-
{
-
cout <<"void operator delete[] (void* ptr, void* voidptr2) throw() called; strlen(ptr)="<
-
return ;
-
}
-
};
-
-
-
-
//#if defined(NEW_ARRAY)
-
-
int main(int argc, char* argv[])
-
{
-
#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 *pArryCon = NULL;
-
int loop = true;
-
while (loop)
-
{
-
size_t input = 0;
-
cin.sync();
-
cout.clear();
-
cout<<"\n input %%u for input number:"<
-
cin >> input;
-
cout <<"input = "<
-
try
-
{
-
switch(input)
-
{
-
case 1:
-
{
-
g_exception = 0;
-
cout <<"paBase = (superClass *) operator new[](2 * superClassSize + 4);"<<" sizeof(superClass) = "<
-
superClass * paBase1 = (superClass *) operator new[](2 * superClassSize + 4);
-
superClass * pArryCon1 = new (paBase1) superClass[2];
-
pArryCon1->~superClass();
-
(pArryCon1 + 1)->~superClass();
-
operator delete[](paBase1);
-
paBase1 = NULL;
-
cout <<"paBase1 = NULL;"<
-
break;
-
}
-
-
case 2:
-
{
-
g_exception = 0;
-
cout <<"paBase = new superClass[2];"<<" sizeof(superClass) = "<
-
superClass * paBase2 = new superClass[2];
-
delete [] paBase2;
-
paBase2 = NULL;
-
break;
-
}
-
-
case 3:
-
{
-
g_exception = 0;
-
cout <<"paBase3 = (superClass *)superClass::operator new[](2 * superClassSize);"<<" sizeof(superClass) = "<
-
superClass * paBase3 = (superClass *)superClass::operator new[](2 * superClassSize);
-
superClass::operator delete[](paBase3);
-
paBase3 = NULL;
-
break;
-
}
-
-
case 4:
-
{
-
g_exception = 0;
-
cout <<"const superClass * paBase4 = new (nothrow) const superClass[2];"<<" sizeof(superClass) = "<
-
const superClass * paBase4 = new (nothrow) const superClass[2];
-
delete [] paBase4;
-
paBase4 = NULL;
-
break;
-
}
-
-
case 5:
-
{
-
g_exception = 0;
-
cout <<"superClass * paBase5 = new (nothrow) superClass[2];"<<" sizeof(superClass) = "<
-
superClass * paBase5 = new (nothrow) superClass[2];
-
delete [] paBase5;
-
paBase5 = NULL;
-
break;
-
}
-
-
case 6:
-
{
-
g_exception = 0;
-
cout <<"superClass * paBase6 = (superClass *)operator new[](2 * superClassSize);"<<" sizeof(superClass) = "<
-
superClass * paBase6 = (superClass *)operator new[](2 * superClassSize);
-
operator delete[](paBase6);
-
paBase6 = NULL;
-
break;
-
}
-
-
case 7:
-
{
-
g_exception = 0;
-
cout <<"superClass * paBase7 = (superClass *) operator new[](2 * superClassSize + 4);"<<" sizeof(superClass) = "<
-
superClass * paBase7 = (superClass *) operator new[](2 * superClassSize + 4);
-
const superClass * pArryCon7 = new (paBase7) const superClass[2];
-
delete [] pArryCon7;
-
paBase7 = NULL;
-
break;
-
}
-
-
case 8:
-
{
-
g_exception = 0;
-
cout <<"myclass * paBase8 = (myclass *) operator new[](2 * sizeof(myclass) + 4);"<<" sizeof(myclass) = "<
-
myclass * paBase8 = (myclass *) operator new[](2 * sizeof(myclass) + 4);
-
myclass * pArryCon8 = new (paBase8) myclass[2];
-
delete [] pArryCon8;
-
paBase8 = NULL;
-
break;
-
}
-
-
case 9:
-
{
-
g_exception = 0;
-
cout <<"paBase = new myclass[2];"<<" sizeof(myclass) = "<
-
myclass * paBase9 = new myclass[2];
-
delete [] paBase9;
-
paBase9 = NULL;
-
break;
-
}
-
-
case 10:
-
{
-
g_exception = 0;
-
cout <<"paBase = (superClass *) operator new[](2 * superClassSize + 4);"<<" sizeof(superClass) = "<
-
superClass * paBase10 = (superClass *)superClass::operator new[](2 * superClassSize + 4);
-
superClass * pArryCon10 = new (paBase10) superClass[2];
-
delete [] pArryCon10;
-
paBase10 = NULL;
-
break;
-
}
-
-
case 'q':
-
loop = false;
-
default:
-
break;
-
}
-
}
-
catch (...)
-
{
-
cout <<"exception when input = "<
-
}
-
}
-
#endif//NEW_ARRAY
-
return true;
-
}
示例new[]/delete[]在正常运行,即关闭宏
NEW_FAIL_OPERATOR时的输出结果:
-
input %%u for input number:
-
input = 1
-
paBase = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
paBase1 = NULL;
-
-
input %%u for input number:
-
input = 2
-
paBase = new superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
-
-
input %%u for input number:
-
input = 3
-
paBase3 = (superClass *)superClass::operator new[](2 * superClassSize); sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=24
-
void operator delete[] (void* ptr) throw () called; strlen(p)=33
-
-
input %%u for input number:
-
input = 4
-
const superClass * paBase4 = new (nothrow) const superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
-
-
input %%u for input number:
-
input = 5
-
superClass * paBase5 = new (nothrow) superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
-
-
input %%u for input number:
-
input = 6
-
superClass * paBase6 = (superClass *)operator new[](2 * superClassSize); sizeof(superClass) = 12
-
-
input %%u for input number:
-
input = 7
-
superClass * paBase7 = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
-
-
input %%u for input number:
-
input = 8
-
myclass * paBase8 = (myclass *) operator new[](2 * sizeof(myclass) + 4); sizeof(myclass) = 4
-
myclass(), myclass constructed
-
myclass(), myclass constructed
-
~myclass(), myclass deconstructed
-
~myclass(), myclass deconstructed
-
-
input %%u for input number:
-
input = 9
-
paBase = new myclass[2]; sizeof(myclass) = 4
-
myclass(), myclass constructed
-
myclass(), myclass constructed
-
~myclass(), myclass deconstructed
-
~myclass(), myclass deconstructed
-
-
input %%u for input number:
-
input = 10
-
paBase = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=28
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
示例new[]/delete[]在构造函数第二次运行抛出异常时,即打开宏
NEW_FAIL_OPERATOR时的输出结果:
-
input %%u for input number:
-
input = 1
-
paBase = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr, void* voidptr2) throw() called; strlen(ptr)=1;strlen(voidptr2)=1
-
exception when input = 1 next sequence
-
-
-
input %%u for input number:
-
input = 2
-
paBase = new superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
-
exception when input = 2 next sequence
-
-
-
input %%u for input number:
-
input = 3
-
paBase3 = (superClass *)superClass::operator new[](2 * superClassSize); sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=24
-
void operator delete[] (void* ptr) throw () called; strlen(p)=33
-
-
input %%u for input number:
-
input = 4
-
const superClass * paBase4 = new (nothrow) const superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw() called; strlen(p)=1
-
exception when input = 4 next sequence
-
-
-
input %%u for input number:
-
input = 5
-
superClass * paBase5 = new (nothrow) superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw() called; strlen(p)=1
-
exception when input = 5 next sequence
-
-
-
input %%u for input number:
-
input = 6
-
superClass * paBase6 = (superClass *)operator new[](2 * superClassSize); sizeof(superClass) = 12
-
-
input %%u for input number:
-
input = 7
-
superClass * paBase7 = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr, void* voidptr2) throw() called; strlen(ptr)=1;strlen(voidptr2)=1
-
exception when input = 7 next sequence
-
-
-
input %%u for input number:
-
input = 8
-
myclass * paBase8 = (myclass *) operator new[](2 * sizeof(myclass) + 4); sizeof(myclass) = 4
-
myclass(), myclass constructed
-
exception when input = 8 next sequence
-
-
-
input %%u for input number:
-
input = 9
-
paBase = new myclass[2]; sizeof(myclass) = 4
-
myclass(), myclass constructed
-
exception when input = 9 next sequence
-
-
-
input %%u for input number:
-
input = 10
-
paBase = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=28
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr, void* voidptr2) throw() called; strlen(ptr)=1;strlen(voidptr2)=1
-
exception when input = 10 next sequence
根据输出结果我们进行分类分析:
(1)形式operator new[](size), new (pAddress) Class[Num]和operator delete[](pAddress)的分析.其中,
Class对new[]和delete[]进行了操作符重载. 对应示例中的代码为:
-
g_exception = 0;
-
cout <<"paBase = (superClass *) operator new[](2 * superClassSize + 4);"<<" sizeof(superClass) = "<
-
superClass * paBase1 = (superClass *) operator new[](2 * superClassSize + 4);
-
superClass * pArryCon1 = new (paBase1) superClass[2];
-
pArryCon1->~superClass();
-
(pArryCon1 + 1)->~superClass();
-
operator delete[](paBase1);
-
paBase1 = NULL;
-
cout <<"paBase1 = NULL;"<
-
break;
示例在正常运行,即关闭宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
paBase = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
paBase1 = NULL;
示例在构造函数第二次运行抛出异常时,即打开宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
paBase = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr, void* voidptr2) throw() called; strlen(ptr)=1;strlen(voidptr2)=1
-
exception when input = 1 next sequence
根据结果分析,
示例(1)的代码在异常版本中执行到程序superClass * pArryCon1 = new (paBase1) superClass[2]就异常不在执行后序的代码.
i.代码superClass * paBase1 = (superClass *) operator new[](2 * superClassSize + 4) -> 调用库函数void *__CRTDECL operator new[](size_t count) _THROW1(std::bad_alloc), 并且正常和异常版本都没有调用superClass的构造函数;特别注意2 * superClassSize + 4中的 4 = sizeof(int *), 表示在使用 operator new[]需要多分配一个指针内存, 否则在释放内存时将导致栈异常.
ii.代码superClass * pArryCon1 = new (paBase1) superClass[2] -> 先调用superClass类的void* operator new[](size_t s, void* object) throw(), 再调用superClass[0]的构造函数, 最后调用superClass[1]的构造函数;
分析示例(1)的异常版本,我们前面做了假设, 在superClass[1]的构造函数superClass()中抛出异常,即在superClass异常抛出后, new (pAddress) Class[NUm]执行了superClass[1]的virtual ~base(), 其后执行superClass[0]的~superClass(), 在执行superClass[0]的virtual ~base()函数, 最后执行superClass类的void operator delete[] (void* ptr, void* voidptr2) throw(), 并退出不执行示例(1)其后序代码,造成了内存的泄漏, 需要注意并此处没有调用superClass[1]的~superClass(), 因为对象没有构造成功.这告诉我们,内存使用在没有非常有把握情况下, 尽可能使用原来new[]/delete[]语义, 否则容易造成内存操作失误.
iii.代码pArryCon1->~superClass() -> 先执行superClass[0]的~superClass(),在执行superClass[0]的virtual ~base().
iv.代码pArryCon1->~superClass() -> 先执行superClass[1]的~superClass(),在执行superClass[1]的virtual ~base(), 对比(i)(iii) 看出调用的都是类的析构函数, 并且析构函数的执行顺序相似.
v.代码operator delete[](paBase1) -> 调用库函数void operator delete[]( void * p ), 请区别因为此处没有调用superClass类的void operator delete[] (void* p) throw (); 如果将operator delete[](paBase1)改成operator delete[](pArryCon1), 将发生栈非法, 用编译器查看到paBase1只是内存, pArryCon1含有虚表即被new被放置过.
示例(1)在正常调用与发生异常情况下, 产生了不同结果, 同时在异常发生时造成了内存泄漏, superClass类的void operator delete[] (void* ptr, void* voidptr2) throw()用于编译器在new放置式异常的调用函数.
(2)形式Class pAddress = new Class[Num]和delete[](pAddress)的分析.其中Class重载了new[]/delete[]操作符对应示例中的代码为:
-
cout <<"paBase = new superClass[2];"<<" sizeof(superClass) = "<
-
superClass * paBase2 = new superClass[2];
-
delete [] paBase2;
-
paBase2 = NULL;
示例在正常运行,即关闭宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
paBase = new superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
示例在构造函数第二次运行抛出异常时,即打开宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
paBase = new superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
-
exception when input = 2 next sequence
根据结果分析,形式
new Class[Num]和delete[](pAddress)在new Class[Num]是否发生异常产生不同的行为, 若在语句superClass * paBase2 = new superClass[2]发生异常,将进行异常处理后退出. 我们进行代码语句分析:
i. 语句superClass * paBase2 = new superClass[2] -> 先调用superClass类的void* operator new[](size_t count) throw(std::bad_alloc), 在调用superClass[0]的构造函数,最后调用superClass[1]的构造函数. 顺序是先申请内存,在调用对象构造函数.
分析示例(2)的异常版本,我们前面做了假设, 在superClass[1]的构造函数superClass()中抛出异常,即在superClass异常抛出后,语句superClass * paBase2 = new superClass[2]先执行了superClass[1]的virtual ~base(), 其后执行superClass[0]的~superClass(), 在执行superClass[0]的virtual ~base()函数, 最后执行superClass类的void operator delete[] (void* ptr) throw (), 而不是执行superClass类的void operator delete[] (void* ptr, void* voidptr2) throw(); 需要注意此处没有调用superClass[1]的~superClass(), 因为对象没有构造成功. new[]/delete[]相互对应, 即便异常也没有造成内存泄漏, 这就为什么操作符重载new[]也要同时重载对应的delete[].
ii.语句delete [] paBase2 -> 先执行superClass[1]的~superClass();在执行superClass[1]的virtual ~base(); 其后执行superClass[0]的~superClass(); 然后在执行superClass[0]的virtual ~base(); 最后执行superClass类的void operator delete[] (void* ptr) throw ().执行的函数和执行的顺序是非常重要的,我们要注意.
示例(2)分析知道new[]/delete[]是需要要么一起被重载,要么都不重载, 数组对象追寻过程中,有一个未创建成功, 数组中其他创建成功的对象也会被析构. 数组对象构造按数组内成员的顺序从小到大,析构则从大到小. 最后我们需要知道, new const Class[num]正常与异常版本的调用行为与new Class[num]是一样的, 只是const关键字需要注意的new const Class[num]也是一样要注意.如const Class *pAddr = new const Class[num]的写法与操作.请对比区别示例(4)的行为.
(3)形式Class::operator new[](size)和Class::operator delete[](pAddress)的分析;其中Class对new[]/delete[]进行了重载. 对应示例中的代码为:
-
cout <<"paBase3 = (superClass *)superClass::operator new[](2 * superClassSize);"<<" sizeof(superClass) = "<
-
superClass * paBase3 = (superClass *)superClass::operator new[](2 * superClassSize);
-
superClass::operator delete[](paBase3);
-
paBase3 = NULL;
示例在正常运行,即关闭宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
paBase3 = (superClass *)superClass::operator new[](2 * superClassSize); sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=24
-
void operator delete[] (void* ptr) throw () called; strlen(p)=33
示例在构造函数第二次运行抛出异常时,即打开宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
paBase3 = (superClass *)superClass::operator new[](2 * superClassSize); sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=24
-
void operator delete[] (void* ptr) throw () called; strlen(p)=33
根据结果我们进行语句分析:
i. 语句superClass * paBase3 = (superClass *)superClass::operator new[](2 * superClassSize) -> 只有调用superClass类的void* operator new[](size_t count) throw(std::bad_alloc),没有调用对象构造函数.
ii.语句superClass::operator delete[](paBase3) -> 只有调用superClass类的void operator delete[] (void* ptr) throw (), 没有调用对象析构函数.
示例(3)看出, 当用户调用operator new[]/operator delete[]时, 只是类似普通的static类成员函数, 不会调用类的构造与析构函数.
(4)形式new (nothrow) const Class[Num]和delete[] (pAddress)的分析.其中Class对new[]/delete[]进行了重载. 对应示例中的代码为:
-
cout <<"const superClass * paBase4 = new (nothrow) const superClass[2];"<<" sizeof(superClass) = "<
-
const superClass * paBase4 = new (nothrow) const superClass[2];
-
delete [] paBase4;
-
paBase4 = NULL;
示例在正常运行,即关闭宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 4
-
const superClass * paBase4 = new (nothrow) const superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
示例在构造函数第二次运行抛出异常时,即打开宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 4
-
const superClass * paBase4 = new (nothrow) const superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw() called; strlen(p)=1
-
exception when input = 4 next sequence
根据示例(4)结果, new[]其实有几种写法, 更可怕的是, 还可以有const类型的.在示例(4)异常版本中,const superClass * paBase4 = new (nothrow) const superClass[2]执行后将退出. 我们进行语句分析:
i.语句const superClass * paBase4 = new (nothrow) const superClass[2] -> 首先调用superClass类的void* operator new[](size_t count, const std::nothrow_t&) throw(), 在调用superClass[0]的构造函数,最后调用superClass[1]的构造函数. 注意此处没有调用superClass类的void* operator new[](size_t count) throw, 请区别于new Class[Num]形式.
分析示例(4)的异常版本,我们前面做了假设, 在superClass[1]的const superClass * paBase4 = new (nothrow) const superClass[2] 中抛出异常,即在superClass异常抛出后,语句const superClass * paBase4 = new (nothrow) const superClass[2]在执行superClass()后, 执行了superClass[1]的virtual ~base(), 其后执行superClass[0]的~superClass(), 在执行superClass[0]的virtual ~base()函数, 最后执行superClass类的void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw(), 不是void operator delete[] (void* ptr) throw (), 也不是superClass类的void operator delete[] (void* ptr, void* voidptr2) throw(); 需要注意此处没有调用superClass[1]的~superClass(), 因为对象没有构造成功.
ii.语句delete [] paBase4 -> 与示例(2) ii.相似.
示例(4)让我们知道, const 类型是可以new (nothrow) const Class[Num]出来的, 并且调用的operator new也是与new Class[Num]不一样,发生异常后, 编译器调用的处理operator delete[]也不一样.其中类中的成员函数void* operator new[](size_t count, const std::nothrow_t&) throw(), void operator delete[] (void* ptr) throw ()和void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw()都与new 的nothrow相关.
(5)形式new const Class[Num]和delete[] (pAddress)的分析.其中Class对new[]/delete[]进行了重载.对应示例中的代码为:
-
cout <<"superClass * paBase5 = new (nothrow) superClass[2];"<<" sizeof(superClass) = "<
-
superClass * paBase5 = new (nothrow) superClass[2];
-
delete [] paBase5;
-
paBase5 = NULL;
示例在正常运行,即关闭宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 5
-
superClass * paBase5 = new (nothrow) superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
示例在构造函数第二次运行抛出异常时,即打开宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 5
-
superClass * paBase5 = new (nothrow) superClass[2]; sizeof(superClass) = 12
-
void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s=28
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw() called; strlen(p)=1
-
exception when input = 5 next sequence
根据示例(5)结果分析, new (nothrow) Class[num] 与new (nothrow) const Class[num]调用的函数在正常与异常版本相似. 语句superClass * paBase5 = new (nothrow) superClass[2]行为与
示例(4)i. 相似; delete [] paBase5与
示例(4)ii.相似. 这真是让人抓狂..
(6)形式operator new[](sizeof(Class)*num)和operator delete[](pAddress)的分析.其中Class对new[]/delete[]进行了重载.对应示例中的代码为:
-
cout <<"superClass * paBase6 = (superClass *)operator new[](2 * superClassSize);"<<" sizeof(superClass) = "<
-
superClass * paBase6 = (superClass *)operator new[](2 * superClassSize);
-
operator delete[](paBase6);
-
paBase6 = NULL;
示例在正常运行,即关闭宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 6
-
superClass * paBase6 = (superClass *)operator new[](2 * superClassSize); sizeof(superClass) = 12
示例在构造函数第二次运行抛出异常时,即打开宏
NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 6
-
superClass * paBase6 = (superClass *)operator new[](2 * superClassSize); sizeof(superClass) = 12
根据示例(6)结果分析,superClass * paBase6 = (superClass *)operator new[](2 * superClassSize) -> 调用库函数void *__CRTDECL operator new[](size_t count) _THROW1(std::bad_alloc), 并且不调用类的构造函数; operator delete[](paBase6) -> 调用库函数void operator delete[]( void * p ),并且不调用类的析构函数. 说明当用户使用operator new[]/delete[]时, 只是当成类似普通函数或者成员函数;与
示例(3)对比发现, 要调用类的operator new/operator delete需要加命名空间.
(7)形式operator new[](size), new (pAddress) const Class[Num]和delete [] (pAddress)的分析.其中Class对new[]/delete[]进行了重载.对应示例中的代码为:
-
cout <<"superClass * paBase7 = (superClass *) operator new[](2 * superClassSize + 4);"<<" sizeof(superClass) = "<
-
superClass * paBase7 = (superClass *) operator new[](2 * superClassSize + 4);
-
const superClass * pArryCon7 = new (paBase7) const superClass[2];
-
delete [] pArryCon7;
-
paBase7 = NULL;
示例在正常运行,即关闭宏NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 7
-
superClass * paBase7 = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
示例在构造函数第二次运行抛出异常时,即打开宏NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 7
-
superClass * paBase7 = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr, void* voidptr2) throw() called; strlen(ptr)=1;strlen(voidptr2)=1
-
exception when input = 7 next sequence
根据示例(7)结果分析,new (pAddress) Class[num]与new (pAddress) const Class[num]正常与异常版本的调用函数都相似, operator new[]的两种放置式写法行为类似, 但是需要区别关键字const相关的行为.
(8)形式operator new[](size), new (pAddress) Class[Num]和delete [] (pAddress)的分析.其中Class没有对new[]/delete[]进行重载, 对应示例中的代码为:
-
cout <<"myclass * paBase8 = (myclass *) operator new[](2 * sizeof(myclass) + 4);"<<" sizeof(myclass) = "<
-
myclass * paBase8 = (myclass *) operator new[](2 * sizeof(myclass) + 4);
-
myclass * pArryCon8 = new (paBase8) myclass[2];
-
delete [] pArryCon8;
-
paBase8 = NULL;
示例在正常运行,即关闭宏NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 8
-
myclass * paBase8 = (myclass *) operator new[](2 * sizeof(myclass) + 4); sizeof(myclass) = 4
-
myclass(), myclass constructed
-
myclass(), myclass constructed
-
~myclass(), myclass deconstructed
-
~myclass(), myclass deconstructed
示例在构造函数第二次运行抛出异常时,即打开宏NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 8
-
myclass * paBase8 = (myclass *) operator new[](2 * sizeof(myclass) + 4); sizeof(myclass) = 4
-
myclass(), myclass constructed
-
exception when input = 8 next sequence
根据示例(8)结果分析, new放置式形式new (pAddress) Class[Num]在Class是否重载operator new[]/operator delete[]产生了不同的行为.在示例(8)异常版本中, myclass * pArryCon8 = new (paBase8) myclass[2]抛出异常退出.
i.语句myclass * paBase8 = (myclass *) operator new[](2 * sizeof(myclass) + 4) -> 调用库函数void *__CRTDECL operator new[](size_t count) _THROW1(std::bad_alloc), 不调用类的构造函数.其中 4 = sizeof(int *).
ii.语句myclass * pArryCon8 = new (paBase8) myclass[2] -> 先调用库函数inline void *__CRTDECL operator new[](size_t, void *_Where) _THROW0(); 在调用myclass[0]的构造函数;最后在调用myclass[1]的构造函数.
在示例(8)异常版本中, myclass * pArryCon8 = new (paBase8) myclass[2] -> 先调用库函数inline void *__CRTDECL operator new[](size_t, void *_Where) _THROW0(); 在调用myclass[0]的构造函数, 然后抛出std::bad_alloc异常, 最后调用库函数inline void __CRTDECL operator delete[](void *, void *) _THROW0().
iii.语句delete [] pArryCon8 -> 先调用myclass[1]析构函数,在调用myclass[0]析构函数, 最后调用库函数void operator delete[]( void * p ).
示例(8)是在没有重载operator new[]/operator delete[]情况下的new []的放置式行为,是平时我们使用new []的放置式行为, 在使用operator new[](2 * sizeof(myclass) + 4)后, 如果放置式发生异常, 将产生内存泄漏. 这也是我们平时使用放置式需要注意的.
(9)形式new Class[num]和delete [] (pAddress)的分析.其中Class没有对new[]/delete[]进行重载,对应示例中的代码为:
-
cout <<"paBase = new myclass[2];"<<" sizeof(myclass) = "<
-
myclass * paBase9 = new myclass[2];
-
delete [] paBase9;
-
paBase9 = NULL;
示例在正常运行,即关闭宏NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 9
-
paBase = new myclass[2]; sizeof(myclass) = 4
-
myclass(), myclass constructed
-
myclass(), myclass constructed
-
~myclass(), myclass deconstructed
-
~myclass(), myclass deconstructed
示例在构造函数第二次运行抛出异常时,即打开宏NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 9
-
paBase = new myclass[2]; sizeof(myclass) = 4
-
myclass(), myclass constructed
-
exception when input = 9 next sequence
示例(9)是我们大家平时最经常用的形式,最有可能在new class[num]时候抛出异常.我们进行代码分析:
i.语句myclass * paBase9 = new myclass[2] -> 先调用库函数void *__CRTDECL operator new[](size_t count) _THROW1(std::bad_alloc),在调用myclass[0]的构造函数, 最后调用myclass[1]的构造函数.
在示例(9)的异常版本中,myclass * paBase9 = new myclass[2] -> 先调用库函数void *__CRTDECL operator new[](size_t count) _THROW1(std::bad_alloc),在调用myclass[0]的构造函数,当myclass[0]的构造函数抛出异常后, 调用库函数void operator delete[]( void * p );然后退出.
ii.语句 delete [] paBase9 -> 先调用myclass[1]的析构函数, 在调用myclass[0]的构造函数, 最后调用库函数void operator delete[]( void * p );
在示例(9)展示了平时C++ new []的用法和调用库函数的简单过程, 展示为什么new不成功不会造成内存泄漏,希望我们能知其然知其所以然.
(10)形式operator new[](size), new (pAddress) Class[Num]和operator delete[](pAddress)的分析.对应示例中的代码为:
-
cout <<"paBase = (superClass *) operator new[](2 * superClassSize + 4);"<<" sizeof(superClass) = "<
-
superClass * paBase10 = (superClass *)superClass::operator new[](2 * superClassSize + 4);
-
superClass * pArryCon10 = new (paBase10) superClass[2];
-
delete [] pArryCon10;
-
paBase10 = NULL;
示例在正常运行,即关闭宏NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 10
-
paBase = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=28
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr) throw () called; strlen(p)=1
示例在构造函数第二次运行抛出异常时,即打开宏NEW_FAIL_OPERATOR时的对应输出结果:
-
input %%u for input number:
-
input = 10
-
paBase = (superClass *) operator new[](2 * superClassSize + 4); sizeof(superClass) = 12
-
void* operator new[](size_t count) throw(std::bad_alloc) called; s=28
-
void* operator new[](size_t s, void* object) throw() called; s=28 strlen(object)=33
-
base(), base constructed sizeof(*this)=8; mIndicate = 1
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 1
-
base(), base constructed sizeof(*this)=8; mIndicate = 2
-
superClass(), superClass constructed sizeof(*this)=12; mIndicate = 2
-
virtual ~base(), base deconstructed; mIndicate = 2
-
~superClass(), superClass deconstructed; mIndicate = 1
-
virtual ~base(), base deconstructed; mIndicate = 1
-
void operator delete[] (void* ptr, void* voidptr2) throw() called; strlen(ptr)=1;strlen(voidptr2)=1
-
exception when input = 10 next sequence
根据示例(10)结果并对比示例(1),我们看出他们的行为很类似却有不同, 事实上delete [] pArryCon10相当于 (pArryCon1 + 1)->~superClass()和pArryCon1->~superClass()及operator delete[](paBase1); 的功能组合, 但是真正不相等, 因为delete []在编译器行为中,作了更多的处理,如规定了析构函数调用顺序, 特别是delete中~superClass抛出异常程序将终止. 当然, 组合的操作可以进行异常catch操作等等.
谁是谁非, 剑总在有用的人手上才能发挥其作用, 更甚者手中无剑, 却生剑伤. new/delete 与new[]/delete[]还有更多组合与故事,复杂又艰涩, 我们一直在new/delete路上, 直指前方...