example:Vector
template <class T> class Vector{ private: T* m_elements; int m_size; public: Vector (int size = 0):m_size(size)... ~Void(){delete [] m_elements;} void length(int); int length(){return m_size;} T& operator[](int); };
problem
template <class T>
T& Vector<T>::operator[](int indx){}
-
what should the [] operator do if the index is not valid? index 越界怎么办?
1.)return random memory object 不可以
return m_elements[indx];
2.)return a special error value 返回一个特殊错误值 不是好办法
if (indx < 0 || indx >= m_size){ T* error_marker = new T("some magic value"); return *error_marker; } return m_elements[indx];
*but this throws the baby out with the bath!
x = v[2] + v[4]; //not safe code
3.)just die!
if (indx < 0 || indx >= m_size){ exit(22); } return m_elements[indx];
4.)die gracefully (with autopsy!)
assert(indx >= 0 && indx < m_size); // 不合适 retrun m_elements[indx];
when to use exceptions 好的解决办法
-
many times ,you don't know what should be done
-
if you do anything you'll be wrong
-
solution:turf the problem
make your caller(or its caller...) responsible
how to raise an exception
template<class T>
T& Vector<T>::operator[](int indx){
if(indx < 0 || indx >= m_size){
//throw is a keyword
//exception is raised at this point
throw --someting--
}
return m_elements[indx];
}
what do you throw?
//what do you have? Data!
//define a class to represent the error
class VectorIndexError{ public: VectorIndexError(int v):m_badValue{} ~VectorIndexError(){} void diagnostic(){ cerr << "index" << m_badValue <<"out of range"; } private: int m_badValue; };
how to raise an exception
template<class T> T& Vector<T>::operator[](int indx){ if(indx < 0 || indx >= m_size){ //VectorIndexError //throw e; throw VectorIndeError(indx); // VectorIndeError对象在堆栈里面 } return m_elements[indx]; }
what about your caller?
-
case 1 Doesn't care
-
code never even suspects a problem
int func(){ Vector<int> v(12); v[3] = 5; int i = v[42];//out of range //control never gets here! return i*5; }
-
-
case2 cares deeply
void outer(){ try{ func(); func2(); // func2 不执行 }catch(VectorIndexError& e){ e.diagnostic(); //this excpetion does not propagete } cout << "control is here after exception" }
-
case3 mildly interested
void outer2(){ String err("exception caught"); try{ func(); }catch(VextorIndexError){ cout << err; throw; //propagate the exception } }
-
case4 does't care about the particulars
void outer3(){ try { outer2(); }catch(...){ // 捕捉所有异常 //...catches **all** exceptions! cout << "the exception stops here" } }
what happened?
review
- throw statement raise the exception
- control propagates back to first handler for that exception
- propagation follows the call chain
- objects on stack are properly destroyed
- "throw exp"
- throws values for matching
- "throw"
- reraises the exception being handled
- valid only within a handler