设为首页 加入收藏

TOP

c++对象模型 模板 异常处理 执行期类型识别(一)
2023-07-23 13:33:11 】 浏览:57
Tags:模板 常处理

template

声明

? 当我们声明一个template class、template class memberfunction等,会发生何事?

? 现有如下片段:

template <class Type>
class Point
{
public:
    enum Status{ unallocated, normalized };
    
    Point( Type x = 0.0, Type y = 0.0, Type z = 0.0 );
    ~Point();
    
    void* operator new( size_t );
    void operator delete( void*, size_t );
    
    //...
    
private:
    static Point<Type> *freeList;
    static int chunkSize;
    Type _x, _y, _z;
}

? 声明一个template class,在程序中编译器对其并没有任何反应。换句话说,上述的data member其实并不可用

实例化

  • 我们需要显示地指定类型才可使用data member:
Point::Status s;

Point<float>::freeList;

//如下会产生第二个freeList实例
Point<double>::freeList;

//定义指针指向特定实例,程序中啥也没发生。因为编译器不需要知道与该class有关的任何member数据,也没必要初始化template实例,且指针可以为0
Point< float >* ptr = 0;

//reference则不同,它需要实例化,因为reference是需要绑定对象的
const Point<float>& ref = 0;

//扩展
Point<float> temp( (float) 0 );
const Point<float>& ref = temp;

//导致实例化
const Point<float> origin;

? 对于int和long相同的架构中,以下两个实例化c++standard并未对此进行强制规定应实例化一个还是两,不过大部分编译器都是实例化两个:

Point<int> pi;
Point<long> pi;
  • 目前的编译器,面对一个template的处理是完全解析但不做类型检验;只有在实例化操作发生时才做类型检验
  • template class内的member functions只有在被使用的时候,才会被实例化

名称决议

  • 在c++standard规定了template两个不一样的端,分别是定义template(template定义的文件)的程序端和实例化template(使用的特定例子)的程序端

    //定义template端
    //只有一个foo()声明位于定义端内
    extern double foo( double );
    
    template< class type >
    class A
    {
    public:
        void do1()
        {
            _member = foo( _val );
        }
        
        type do2()
        {
            return foo( _member );
        }
        //...
        
    private:
        int _val;
        type _member;
    }
    
    //实例化端
    //两个foo()声明在实例化端内
    extern int foo( int );
    
    template< class type >
    class A
    {
    public:
        void do1()
        {
            _member = foo( _val );
        }
        
        type do2()
        {
            return foo( _member );
        }
        //...
        
    private:
        int _val;
        type _member;
    }
    
    A<int> a;
    
    //应该调用extern double foo( double )。因为_val的类型与template type参数类型无关
    a.do1();
    
    //应调用extern int foo( int )。因为_member与template type参数类型有关
    a.do2();
    
  • template中,对一个nonmenber name的决议结果是根据此name的使用是否与"用以实例化该template的参数类型"有关来决定:

    • 若其使用互不相关,则使用定义端来决定name
    • 若其使用有关联,则使用实例化端来决定name
  • 编译器必须保持两个端上下文(scope contexts):

    • 定义端。专注一般的template class
    • 实例化端。专注特定实例

异常处理

  • 想要支持异常处理,编译器的主要工作是找出catch子句以处理被抛出来的exception

  • 异常处理由三个主要组件构成:

    1. 一个throw子句。它再程序某处发出一个exception,被抛出的exception可为内建类型,亦可为自定类型
    2. 一个或多个catch子句。每个catch子句都为一个exception handler。表示此子句准备处理某种类型的exception,且在封闭的大括号区段中提供实际的处理程序
    3. 一个try区段。他被围绕一系列叙述句,这些叙述句可能会引发catch子句起作用
  • 当一个exception被抛出,控制权会从函数调用中被释放出,并寻找一个吻合的catch子句。若没有则调用默认处理例程terminate()。当控制权被释放,堆栈中每个函数调用也就被推离,被推离前函数的local class objects的destructor会被调用

    Point* mumble
    {
        //区域一
        Point* pt1, * pt2;
        //若一个exception于此被抛出,mumble()会被推出堆栈
        pt1 = foo();	
        if( !pt1 ) return 0;
        
        //区域二
        Point p;
        //若一个exception于此被抛出,在推出mumble()前需要先调用p的destructor
        pt2 = foo();
        if( !pt2 ) return pt1;
    }
    
    • 支持以上exception handling,编译器有两种策略:
      1. 把两个区域(上面两个exception)以个别的"将被摧毁的local objects"链表(在编译器准备妥当)联合起来
      2. 让两个区域共享同一个链表,该链表在执行期扩大或缩小
    • 一个函数可以分为多个区段:
      1. try以外的区域,且没有active local objects
      2. try以外的区域,但有一个以上的active local objects需要析构
      3. try以内的区域

? 现有一函数含有对一块共享内存的locking和unlocking操作,此时异常处理不保证能正确运行:

void mumble( void* arena )
{
    Point* p = new Point;
    smLock( arena );
    
    //若此处有exception被抛出,会产生问题
    //...
    
    smUnLock( arena );
    delete p;
}

//因此我们需要安插default catch子句
void mumble( void* arena )
{
    Point* p = new Point;
    smLock( arena );
    
    try
    {
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇[JSOI2010]连通数 下一篇C++对象模型:g++的实现(一)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目