new 和 delete 是运算符,它们都可以被重载。
重载 new 和 delete 的函数框架如下:
[C++] 纯文本查看 复制代码
//为一个对象分配内存
void *operator new(size_t size)
{
/*执行分配操作。在失败时抛出 bad_alloc类型异常。构造函数自动被调用*/
return pointer_to_memory;
}
//释放对象的内存
void operator delete(void *p)
{
/*释放由 p 指向的内存,析构函数自动被调用*/
}
size_t 是一个可移植的预定义数据类型,一般被定义为 unsigned int ,它可以包含最大可分配的单块内存的大小。
size包含为对象分配的字节数。
重载运算符函数 new 必须返回一个指向它所分配的内存的指针,或者在发生错误时抛出一个 bad_alloc 类型异常。当位一个对象分配内存时,构造函数被自动调用。
delete 函数负责将前面分配的内存释放回系统中。当对象被删除时,对象的析构函数被自动调用。
要为对象数组分配或者释放内存,必须使用下面的 new 和 delete 形式:
[C++] 纯文本查看 复制代码
//为对象数组分配内存
void *operator new[] (size_t size)
{
/*执行分配操作,失败时抛出 bad_alloc 类型异常。数组中每个对象的构造函数被自动调用*/
}
//删除对象数组
void operator delete[] (void *p)
{
/*释放由 p 指向的内存,数组中每个对象的析构函数都被自动调用*/
}
测试代码:
[C++] 纯文本查看 复制代码 #include <iostream>
#include <new>
#include <cstdlib>
using namespace std;
class three_d {
int x, y, z; //三维坐标
public:
three_d() {
x = y = z = 0;
cout << "Constructing 0, 0, 0\n";
}
three_d(int i, int j, int k) {
x = i; y = j; z = k;
cout << "Constructing " << i << ", ";
cout << j << ", " << k;
cout << '\n';
}
~three_d() { cout << "Destructing\n"; }
void *operator new(size_t size);
void *operator new[](size_t size);
void operator delete(void *p);
void operator delete[](void *p);
void show();
};
//重载tree_d的运算符new
void *three_d::operator new(size_t size)
{
void *p;
cout << "Allocating three_d object.\n";
p = malloc(size);
//在内存分配失败时抛出异常
if(!p) {
bad_alloc ba;
throw ba;
}
return p;
}
//重载 three_d 数组的运算符new
void *three_d::operator new[](size_t size)
{
void *p;
cout << "Allocating array of three_d objects.\n";
//在内存分配失败时抛出异常
p = malloc(size);
if (!p) {
bad_alloc ba;
throw ba;
}
return p;
}
//重载 three_d 的运算符delete
void three_d::operator delete(void *p)
{
cout << "Deleting three_d object.\n";
free(p);
}
//重载 three_d 数组的运算符delete
void three_d::operator delete[](void *p)
{
cout << "Deleting array of three_d objects.\n";
free(p);
}
//输出x,x,z的坐标值
void three_d::show()
{
cout << x << " ";
cout << y << " ";
cout << z << endl;
}
int main()
{
three_d *p1, *p2;
try {
p1 = new three_d[3]; //为对象数组分配内存
p2 = new three_d(5, 6, 7); //为单个对象分配内存
}
catch (bad_alloc ba) {
cout << "Allocation error.\n";
return 1;
}
p1[1].show();
p2->show();
delete [] p1; //删除数组
delete p2; //删除对象
return 0;
}
运行输出:./reload_newdel
Allocating array of three_d objects.
Constructing 0, 0, 0
Constructing 0, 0, 0
Constructing 0, 0, 0
Allocating three_d object.
Constructing 5, 6, 7
0 0 0
5 6 7
Destructing
Destructing
Destructing
Deleting array of three_d objects.
Destructing
Deleting three_d object. 在输出中,前面 3 条 Constructing 是在为对象数组分配内存时输出的。数组中共包含了 3 个 three_d 类型对象,在为数组分配内存时,数组中的每个成员的构造函数将被自动调用。最后一跳
Constructing 5, 6, 7 信息是为创建单独一个 three_d 类型对象时输出的。同理,前面 3 条提示信息 Destrucing 是在删除数组时输出的,析构函数也都被自动调用;而最后一条 Destrucing 由删除单个对象时输出。
注意:new 和 delete 这两个运算符的重载是与类相关的。如果对其他类型数据使用这些运算符,那么使用默认的 new 和 delete,比如在 main() 中加入 int *f = new int; 这条语句,那么默认的的运算符 new 将被执行,而不是使用上面的重载形式。
最后一点,也可以在全局作用域内重载 new 和 delete 。定义全局运算符的方法是将 operator 函数声明在所有类的定义之外。在这种情况下,C++ 中默认的运算符 new 和 delete 都将被忽略,而一致都采用全局重载形式。当然,和局部变量的原理一样,如果你同时在某个类中也定义了它自己的重载 new 和 delete,那么在为该类分配对象内存和释放对象内存时,使用的是类中定义的重载 new 和 delete。而对于其他类,使用的仍然是全局作用域中的 new 和 delete 。 |