operator new []
class X
{
public:
X(){
cout<<"X()"<<endl;
}
X(int x, int y):m_x(x), m_y(y)
{}
private:
int m_x;
int m_y;
};
void * operator new[](size_t n)
{
cout<<"n: "<<n<<endl; //无~X()时,n = 16, 有X()时,n = 20
void * ptr = malloc(n);
cout<<"In operator new [] :"<<"ptr = "<<ptr<<endl;
return ptr;
}
X * ptr = new X[2] {X(1, 2), X(3, 4)};
cout<<"After operator new [] :"<<"ptr = "<<ptr<<endl;
![在这里插入图片描述]()
- 当
X未显式定义析构函数,运算符new传入的n = sizeof(X) * num_elem(元素个数), 否则,n = sizeof(X) * num_elem + 4,多申请的4个字节用于存放X对象的个数
- 当
X未显式定义析构函数,malloc产生的指针地址 = 运算符 new返回的地址,否则,malloc产生的指针地址 $\neq$ 运算符 new返回的地址,operator new [] ()函数返回后,运算符new会将该4字节内容赋值为元素的个数
- 上述差异,会导致在new、new[]、delete、delete[]相互对应时产生问题
- 该差异仅取决于其中是否显式定义了
析构函数
- 当自己定义了
void * operator new(size_t n)而未定义void * operator new[](size_t n)时,则X * ptr = new X[2]会调用void * operator new(size_t n)
delete operator & operator delete
- 二者的关系类似于
new operator与operator new
class X
{
public:
X(){
cout<<"X()"<<endl;
}
X(int x, int y):m_x(x), m_y(y)
{}
~X()
{
}
private:
int m_x;
int m_y;
};
void operator delete(void * ptr) //重载operator delete
{
cout<<"In operator delete "<<"ptr = "<<ptr<<endl;
free(ptr);
}
void operator delete [](void * ptr) //重载operator delete[]
{
cout<<"In operator delete []"<<"ptr = "<<ptr<<endl;
free(ptr);
}
//当未定义~X()时,没问题
X * ptr = new X[2];
delete ptr;
//当定义~X()时,出错:由于ptr的值,与实际起初malloc产生的ptr的值不同
delete ptr;
- 使用
free进行释放的地址,一定要和malloc产生的地址值相同,否则会出错
- 当使用
operator new []()运算符函数分配内存时,使用operator delete []()函数,进行释放时,此时传入给operator delete []()函数的地址,即为malloc分配的地址,因此使用free进行释放是正确的,当使用运算符delete释放由new []产生的内存,并且在X中显式定义了析构函数时,此时传入operator delete()中的地址和malloc分配的地址是不同的,因此会导致free释放时出错
- 运算符
delete在释放内存所做的工作:
(1)调用X的析构函数
(2)将待释放的内存地址传给operator delete()函数,有它调用free()函数来进行内存释放工作
- 当使用
delete释放由new []分配的内存时,只会调用1次析构函数,然后将该地址原封不动的传入operator delete()函数,由free()进行释放,当X中显式定义了析构函数时,显然free的地址显然与当初malloc()产生的地址不同,因此会导致释放出错
- 当使用
delete []释放new[]分配的地址时,首先在调用operator delete[]()函数之前会,查看当前地址前4个字节中存放的元素个数的值nums_elem,然后调用nums_elem次析构函数,并将当前地址-4传入operator delete[]()函数中,因此此时释放就是正确的
- 同理,当使用
delete []来释放,由new产生的内存时,将会导致更大的异常,首先当前地址的前4字节存的地址是不确定的,因此调用析构函数的次数是不确定的,并且传入给operator delete []()函数的地址与malloc产生的地址值也是不同的,因此也会导致释放出错
参考文献