Inside the C++ Object Model 读书笔记(七)

Templates

Originally viewed as a support for container classes such as Lists and Arrays, templates are now the

  • generic programming (the Standard Template Library).
  • attribute mix-in where, for example, memory allocation strategies
  • mutual exclusion mechanisms for synchronizing threads ([SCHMIDT94])
  • a technique for template metaprograms

three primary aspects of template support:

  1. Processing of the template declarations
  2. Instantiation of the class object and inline nonmember and member template functions.
  3. Instantiation of the nonmember and member template functions and static template class members.

Template Instantiation

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; 
}; 

when the compiler sees the template class declaration, do nothing. the static data members are not available. Nor is the nested enum or its enumerators.

If we define a pointer to a particular instance, such as

Point< float > *ptr = 0;

again, nothing happens in the program. Because a pointer to a class object is not itself a class object; the compiler does not need to know anything about the layout or members of the class.

const Point< float > &ref = 0; 

result in the instantiation of a float instance of Point, The actual semantics of this definition expand as follows:

// internal expansion 
Point< float > temporary( float (0) ); 
const Point< float > &ref = temporary; 

Member functions that are not used should not be instantiated. Standard C++ requires that member functions be instantiated only if they are used (current implementations do not strictly follow this requirement). There are two main reasons for the use-directed instantiation rule:

  • Space and time efficiency
  • Unimplemented functionality

Error Reporting within a Template

All type-dependent checking involving the template parameters must be deferred until an actual instantiation occurs.
In current implementation, that is, a template declaration has only limited error checking applied to it prior to an instantiation of an actual set of parameters.

Name Resolution within a Template

// scope of the template definition 

extern double foo ( double ); 

template < class type > 
class ScopeRules 
{ 
public: 
   void invariant() { 
      _member = foo( _val ); 
   } 

   type type_dependent() { 
      return foo( _member ); 
   } 
   // ... 
private: 
   int _val; 
   type _member; 
}; 

//scope of the template instantiation 

extern int foo( int ); 
// ... 
ScopeRules< int > sr0; 

The program site of the resolution of a nonmember name within a template is determined by whether the use of the name is dependent on the parameter types used to instantiate the template.

If the use is not dependent, then the scope of the template declaration determines the resolution of the name. If the use is dependent, then the scope of the template instantiation determines the resolution of the name.

This means an implementation must keep two scope contexts:

  • The scope of the template declaration, which is fixed to the generic template class representation
  • The scope of the template instantiation, which is fixed to the representation of the particular instance

The compiler’s resolution algorithm must determine which is the appropriate scope within which to search for the name.

Member Function Instantiation

Difficult aspect of template support is template function instantiation:

  1. How does the implementation find the function definition?
  2. How does the implementation instantiate only those member functions that are actually used by the application?
  3. How does the implementation prevent the instantiation of member definitions within multiple .o files?

the Standard has the following, otherwise puzzling clause in Section 14.3.2:

If a virtual function is instantiated, its point of instantiation is immediately following the point of instantiation for its class.

Exception Handling

The primary implementation task in supporting exception handling (EH): discover the appropriate catch clause to handle the thrown exception

Requirement:

  • implementation to somehow keep track of the active area of each function on the program stack (including keeping track of the local class objects active at that point in the function
  • must provide some method of querying the exception object as to its actual type (this leads directly to some form of runtime type identification (RTTI))
  • needs to be some mechanism for the management of the object thrown—its creation, storage, possible destruction

A Quick Review of Exception Handling

When an exception is thrown, control passes up the function call sequence until either an appropriate catch clause is matched or main() is reached without a handler’s being found, at which point the default handler, terminate(), is invoked

Exception Handling Support

When an exception is thrown, the compilation system must do the following:

  1. Examine the function in which the throw occurred.
  2. Determine if the throw occurred in a try block.
  3. If so, then the compilation system must compare the type of the exception against the type of each catch clause.
  4. If the types match, control must pass to the body of the catch clause.
  5. If either it is not within a try block or none of the catch clauses match, then the system must (a) destruct any active local objects, (b) unwind the current function from the stack, and © go to the next active function on the stack and repeat items 2–5.

Determine if the Throw Occurred within a try Block

A function, recall, can be thought of as a set of regions:

  • A region outside a try block with no active local objects
  • A region outside a try block but with one or more active local objects requiring destruction
  • A region within an active try block
catch( exPoint p ) 
{ 
   // do something 
   throw; 
} 

p is initialized by value with the exception object the same as if it were a formal argument of a function. This means a copy constructor and destructor, if defined or synthesized by the compiler, are applied to the local copy.

Because p is an object and not a reference, the non-exPoint portion of the exception object is sliced off when the values are copied. In addition, if virtual functions are provided for the exception hierarchy, the vptr of p is set to exPoint’s virtual table; the exception object’s vptr is not copied.

p is a local object destroyed at the close of the catch clause. Throwing p would require the generation of another temporary. It also would mean losing the exVertex portion of the original exception. The original exception object is rethrown; any modifications to p are discarded.

catch( exPoint &rp ) 
{ 
   // do something 
   throw; 
} 

refers to the actual exception object.

Any changes made to the exception object within a catch clause are local to the copy and are not reflected within errVer. The actual exception object is destroyed only after the evaluation of a catch clause that does not rethrow the exception.

Runtime Type Identification

The C++ RTTI mechanism provides a type-safe downcast facility but only for those types exhibiting polymorphism (those that make use of inheritance and dynamic binding).

References Are Not Pointers

  • If the reference is actually referring to the appropriate derived class or an object of a class subsequently derived from that class, the downcast is performed and the program may proceed.

  • If the reference is not actually a kind of the derived class, then because returning 0 is not viable, a bad_cast exception is thrown.

simplify_conv_op( const type &rt ) 
{ 
    try { 
      fct &rf = dynamic_cast< fct& >( rt ); 
      // ... 
    } 
    catch( bad_cast ) { 
      // ... mumble ... 
    } 
} 

The typeid operator returns a const reference of type type_info.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值