2. operator new 的行为
答:区分三个不同的 new:
operator new 的错误处理:
默认的 operator new 在内存分配失败时将会抛出 std::bad_alloc 异常; X * pX = new (nothrow) X 在内存分配失败时将会返回 0 . 这种行为可以通过设置 new-handler 来改变. new-handler 是一个回调函数指针, typedef void(*new_handler)(void). 通过 set_new_handler(new_handler) 函数设置回调句柄后, 如果分配内存失败, operator new 将会不断的调用 new-handler 函数, 直到找到足够的内存为止. 为了避免死循环, new-handler 函数必须具备以下行为之一:
3.准备重载 operator new
答:重载 operator new 时需要兼容默认的 operator new 错误处理方式. 另外, C++ Standard 规定当要求的内存为 0 byte 时也应该返回有效的内存地址. 所以 operator new 的重载实现应大致如下:void * operator new(size_t size ... ) { if(size == 0) size = 1; while(1) { ... // allocate memery if(allocate sucessfull) return ... // return the pointer. new_handler curhandler = set_new_handler(0); set_new_handler(curhandler); // get current new handler if(curhandler == 0) (*curhandler)(); else throw std::bad_alloc(); } }
4.重载 operator new
答:opeator new 的重载和其它操作符大不相同.首先, 即使你不重载, 默认的 operator new 也可施用于你的自定义型别上(operator, 也具有此特性), 而其它操作符如果不进行重载就无法使用. 其次, 其它重载其它操作符时参数个数都是固定的, 而 operator new 的参数个数是可以任意的, 只需要保证第一个参数为 size_t, 返回类型为 void * 即可, 而且其重载的参数类型也不必包含自定义类型. 更一般的说, operator new 的重载更像是一个函数的重载, 而不是一个操作符的重载.通过使用不同的参数类型, 可以重载 operator new, 例如 :
void * operator new(size_t size, int x, int y, int z) { ... }
X * pX = new (1, 2, 3) X;
你还可以为 operator new 的重载使用默认值, 其原则和普通函数重载一样, 只要不造成和已存在的形式发生冲突即可. 可能你已经想到了, 你甚至还可以在 operator new 中使用不定参数, 如果你真的需要的话.
void * operator new(size_t size, int x, int y = 0, int z = 0) { ... } X * pX = new (10) X; Y * pY = new (10, 10) Y; Z * pZ = new (10, 10, 10) Z; ... void * operator new(size_t size, ...)
重载 class 专属的 operator new:
为某个 class 重载 operator new 时必须定义为类的静态函数, 因为 operator new 会在类的对象被构建出来之前调用. 即是说调用 operator new 的时候还不存在 this 指针, 因此重载的 operator new 必须为静态的. 当然在类中重载 operator new 也可以添加额外的参数, 并可以使用默认值.另外, 和普通函数一样, operator new 也是可以继承的.
class X{ ... static void * operator new(size_t size); // ... (1) static void * operator new(size_t size, int); // ... (2) }; class Y : public X{ ... }; class Z : public X{ ... static void * operator new(size_t size); // ... (3) }; X * pX1 = new X; // call (1) X * pX2 = ::new X; // call default operator new X * pX3 = new (0) X; // call (2) Y * pY1 = new Y; // call (1) Z * pZ1 = new Z; // call (3) Z * pZ2 = ::new Z; // call default operator new Z * pZ3 = X::new Z; // error, no way to call (1) Z * pZ4 = new (0) Z; // error, no way to call (2)
并且这两种形式的 operator delete 可以同时存在, 当调用 delete px 时, 如果 (1) 式存在的话将调用 (1) 式. 只有在 (1) 式不存在时才会调用 (2) 式. 对第 (2) 种形式的 operator delete, 如果用基类指针删除派生类对象, 而基类的析构函数没有虚拟的时候, size 的值可能是错误的.
转载地址: https://www.douban.com/note/34136464/