[ZZ]重载new/delete 运算符与 重载全局异常处理

来源:互联网 发布:网络理财骗局 编辑:程序博客网 时间:2024/06/08 15:36

目前遇到一个关于template导致编译出错的问题不能解决,在搜索资料的时候意外的找到一篇讲C++和Java区别的文章。虽然与目前的主要工作没有关系,但还是有保存的价值。

 

这里就把他转了过来。

【主要贡献】

    1、文中给出了重载new/delete运算符的格式。

    2、在try...catch 中一旦再抛出异常,那么这个异常将会被全局异常处理机制处理。而这个全局异常处理机制也是可以重载的,文中提出了重载地方法。

【原文地址】http://blog.chinaunix.net/u2/88035/showart_1856854.html

 

C++重载机制中没有被Java继承的思想
  

    显然,Java的缔造者James Gosllin没有同意Bjane Stroustroup的全部观点。他们都是伟大的人物。我这篇文章着重谈一下C++重载机制中的一些,没有被java吸收的,但是是C++精髓的部分。

1. 运算符重载(STL方法库的的基本骨架)
    C++的粉丝视为美酒而Java粉丝视为毒药的东西。观点不同而已。我为什么强调这一点是C++的精髓呢?
    举个例子,我们设计一个算法,熟悉软件工程的朋友可能立即会提出: 首先设计一个虚基类,基类里面实现算法的框架,然后实现一个继承类,来实现具体的一些算法细节,不同的子类有不同的实现,这样算法就可以有几个大的版本。但是问题是,如果算法处理的对象类型不定呢? 那么就把算法用模板来实现。----问题来了,算法处理不同类型的值的时候,需要做不同的处理流程,那么是否每一个继承类的Overriden函数都得为不同的类型设计不同的处理流程呢?(例如数字类型,字符串类型,大的二进制类型都需要不同的处理流程)

    C++在这里给出了一个天才的,通用的处理流程: 把数据类型包装成为能够自描述的,有基本类型语义的"值"!
    听起来有点拗口(可能我的概括有点啰嗦),但是是这样的: 例如我写一个快速排序算法qsort<T>(用模板),写完了以后可以排序所有的基本类型。那么当我需要排序复杂类型(class B)的时候怎么办呢?
    我只需要:(1)重载B类型的比较运算符'<','>','=','=='
                bool operator<(const B& b)
                bool operator>(const B& b)
                bool operator==(const B& b)
                B& operator=(const B&b)
             (2)重载B类型的iostream运算符,例如我需要在排序的过程输出一些信息到控制台或其他地方:
                friend ostream& operator<<(ostream& os,const B&b) (当然要在算法实现里面使用iostream而不是stdio)
这样的话,类型B就成为了一个具有"值"语义的类,可以直接作用于qsort<T>而无需任何修改!

    用虚基类/继承类的话,需要在继承类的覆盖方法里面去实现一个算法细节的小部分,可能导致需要大量的调试,或者不同类型的处理流程之间不具有通用性,算法本省也会变得难以理解。而使用运算符重载,我们在增加一个类型的时候,只需要为这个类型的内部作一些增量的重载函数,算法实体做到了100%通用性。软件工程追求的目的就是鼓励增删而避免修改,不是吗?
    当然,在算法框架设计的方面,"谓词对象"和"算子"的思想在C++的STL库和Java的swing监听对象里面都有体现。

2. 强类型的模板和元类型推导。当然Java1.5版本以后也引入了范型和模板的机制,但是它只用于编译时的正确性检查,运行时的信息仍然是object类动态决定的(只有一套代码)。而C++的模板->代码生成,从头到尾都是编译时的强类型检查(N个实例化类型就产生N套代码,彼此互不影响),因此有了模板的推导功能,以至于可以进行"元编程"的工作。
    有兴趣的朋友可以参考"C++ template"这本书的内容,非常深入的讲解C++模板的制----它和Java的模板机制在实现上有很大的不同,虽然两者都支持范型的概念。

3. 标准库行为重载

    想知道哪里分配的内存没有被释放吗? 我可不想修改已有的程序检查问题,在检查完毕后再删除这些增加的代码,我只想做一个一劳永逸的增量检查,怎么办?
    C++给你提供了!(Java没有的!) 你可以重载标准运算符new/delete,你可以重定义异常处理机制中的默认处理过程!

3.1 new/delete的重载: 
(a)
你可以在不同的作用域层次重载new/delete运算符,例如在一个类定义当中去重载
class B{
public:
void* operator new(size_t s...){
  cout<<"声明一个类B的指针并分配内存/n";
  return ::new(B);
}
void  operator delete(size_t s){
  cout<<"释放类B的一个指针内存/n";
  ::delete s;
}};
能重载delete[] 吗? 重载new[]吗? 可以

(b)使用replacement new
在一个固定的管局内存块上分配和释放
static B place[3];
B* pb=new(place)B;//单个
B* pbv=new(place)B[2];//数组
析构的时候不是delete而是显示调用pb->~B();
可以replacement一个兑现数组:
X* p6=new(a)X[10];

(c)覆盖一般作用域的new/delete,例如某个cpp文件作用域
void* operator new(size_t t){
   cout<<"重载的new/n";
   return (void*)::malloc(t);
}
void operator delete(void* p){
   cout<<"重载的delete/n";
   ::free(p);
}
之后在这个cpp文件里面,new和delete就是调用的这个重载的版本

3.2 异常处理的重载
   我们都知道,try块内部的对象,在try抛出异常时,都能被catch模块之前调用析构函数,发生错误的情况是: 如果在catch的处理流程中,有对象的析构函数发生,仍然是抛出unexpected_exception异常,那么这个异常经常会导致std::terminate()发生,程序可能就退出了。怎么捕捉呢? 异常处理的函数可以用std::set_unexpected()和std::set_terminate()来保存和设置。也就是说,C++的所有标准异常流程都能够被重载。
#include<cstdio>
#include<exception>
#include<iostream>
#include<fstream>
using namespace std;
typedef void(*unexpected_handle)();
void f(){ printf("I get unexpected exception/n"); }
void t(){ printf("I terminate it/n"); }
struct C{
  C(){ printf("ctor/n"); }
  void f(){ throw std::exception(); }
  ~C(){ printf("dtor/n"); }
};
int main(void){
 std::set_unexpected(f);
 std::set_terminate(t);
 try{
  C c1;
  c1.f();
 }catch(...){
  bool ue=std::uncaught_exception();
  printf("catch,b=%d/n",ue);
  C c1;
  c1.f();
 }
 return 0;
}
当一个未知的异常发生时,自定义的函数t()就被调用了。

原创粉丝点击