Exception handling in c++

Directory

1. Differences between Exceptions and Bug s

2. Exception handling in c++ (try... Catch...)

3. How to use custom exception classes

4. Exception Classes in C++ Standard Library

5. try..catch alternative writing and function exception declaration/definition throw()

 

1. Differences between Exceptions and Bug s

"Exceptions" are special cases that we must consider in program development and are the branch of execution that can be expected when the program is running (Note: Exceptions are unavoidable, such as dividing by zero when the program is running; open external files do not exist; array access crosses, etc.);

"Bug" is a bug of the program, which is the way the program does not run as expected (Note: Bug is artificial and avoidable, such as using a wild pointer, not released after the end of the heap array, etc.);

Exceptions or bugs are unexpected situations that may occur during the normal operation of a program.The difference is that "exceptions" can be caught and handled appropriately, and the consequences of "bugs" are unpredictable and require code rewriting.

2. Exception handling in c++ (try... Catch...)

(1) Basic grammar

1 //Exception Basic Syntax
2 try
3 {
4 //Code that may produce an exception, throw an exception through the throw keyword if an exception occurs
5 }
6 catch (exception type)//exception capture, note (...) means catch all exceptions
7 {
8//Code that handles exceptions that are generated by the try statement block
9 }

(2) Basic Rules

1) Multiple catch statements can be followed by the same try statement (in a project, code that may produce exceptions is placed in the try statement block, followed by multiple catch statements);

2) Any type of exception (int, string, object, etc.) can be thrown by throw keyword in a try statement;

3) The catch statement can define the specific exception type to be handled, for example, catch (int) only catches the exception of type int, but no further exception information can be obtained; catch (int a) only catches the exception of type int to obtain further exception information;

4) Different types of exceptions are handled by different catch statements;

5) catch(...) is used to handle all types of exceptions (can only be placed after all catch statements);

6) Any exception can only be caught once;

7) As long as catches are captured once, other catches will have no chance of being captured;

8) The type of throw throwing an exception must exactly match the type of catch catching the exception (no type conversion is possible); if the match is successful, the exception can be caught; otherwise, the catching fails and the program stops executing.

    

In fact, to better understand the two actions of exception throwing and exception capture, we can think of them as function calls, throwing an exception as an argument in a function, and catching an exception as a parameter in a function. This capture can only succeed if the type of the argument strictly matches the type of the parameter.Why imagine a function call, not a real one?The reason is that when a function is called, implicit type conversions can be made when parameters are initialized with arguments; however, when exceptions are caught, the exception types must be strictly matched.*

(3) Logical analysis of throw exception

Situation 1: The exception code is not placed in the try {} statement, which also means that there is no corresponding catch statement, which is actually a normal function call. If an exception is throw n, the program stops executing.

Situation 2: The exception code is placed in the try {throw exception...} statement, which also means that if there is a corresponding catch statement, the exception will be exactly matched to the catch statement when thrown; if the match is successful, the exception can be caught, otherwise the exception cannot be caught and the program stops executing.

After throw throws an exception, strictly match the exception type caught by each catch statement from top to bottom in the function where the exception occurs to determine whether the exception can be caught.

(1) If an exception can be caught in a function, the program proceeds down;

(2) If an exception cannot be caught in a function, the unhandled exception will propagate up the function call stack until the exception is caught, or the program will stop executing;

Summary: Exceptions throw n must be caught by the corresponding catch or the program will stop executing;

    

The above illustration illustrates the execution order after an exception is thrown:

1) throw 1 is thrown in function 3; however, it cannot be caught in function 3, and the exception continues to be thrown in function 2

2) In function function function 2, if the exception is still not caught, the exception continues to be thrown to the outer function function function function 1;

3) In function function 1, the exception is caught and handled by catch, and then the program proceeds down;

Note: If an exception is not caught in function function 1, the exception will be thrown out to the outer function until the exception is caught, or the program will stop executing.(

Code Display:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 double divide(double a, double b)
 7 {
 8     const double delta = 0.000000001;
 9     double ret = 0;
10 
11     if( !((-delta < b) && (b < delta)) )
12     {
13         ret = a / b;
14     }
15     else
16     {
17         throw "Divided by zero..."; 
18     }
19 
20     cout << "divide(double a, double b)" << endl;
21      
22     return ret;
23 }
24 
25 double ExceptionFunc()
26 {
27     double d = divide(2, 0);
28     
29     cout << "ExceptionFunc()" << endl;
30     
31     return d;
32 }
33 
34 int main(int argc, char *argv[])
35 {      
36     double d = ExceptionFunc();
37     
38     cout << "result = " << d << endl;
39 
40     return 0;
41 }
42 
43 /**
44  * Run result:
45  * terminate called after throwing an instance of 'char const*'
46  * Aborted (core dumped)
47  */
48  
49 /**
50  * Analysis:
51  * throw "Divided by zero..."; After throwing an exception, the divide(double a, double b) function cannot catch the exception, then the exception continues to be thrown to ExceptionFunc();
52  * In ExceptionFunc(), if the exception cannot be caught, the exception continues to be thrown to main();
53  * If the exception cannot be caught in main(), the program stops executing.
54  */
Scenario 1: Reproduction of an Abnormal List

  

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 double divide(double a, double b)
 7 {
 8     const double delta = 0.000000001;
 9     double ret = 0;
10     
11     try
12     {
13         if( !((-delta < b) && (b < delta)) )
14         {
15             ret = a / b;
16         }
17         else
18         {
19             throw "Divided by zero..."; 
20         }
21     }
22     catch(char const* s)  
23     {
24         cout << s << endl;
25     } 
26         
27     cout << "divide(double a, double b)" << endl;
28  
29     return ret;
30 }
31 
32 double ExceptionFunc()
33 {   
34     double d = divide(2, 0);
35     
36     cout << "ExceptionFunc()" << endl;
37     
38     return d;
39 }
40 
41 int main(int argc, char *argv[])
42 { 
43     ExceptionFunc();
44       
45     cout << "test end!" << endl;
46 
47     return 0;
48 }
49 
50 /**
51  * Run result:
52  * Divided by zero...
53  * divide(double a, double b)
54  * ExceptionFunc()
55  * test end!
56  */
57  
58 /**
59  * Analysis:
60  * throw "Divided by zero..."; After throwing an exception, in the divide(double a, double b), the exception is caught, and the program proceeds downward;
61  *  catch(char const* s)    // throw "Divided by zero..."
62  *  {
63  *     cout << s << endl;
64  *  }   
65  *  cout << "divide(double a, double b)" << endl;
66  *
67  *  divide(2, 0); The function call ends and returns to ExceptionFunc().
68  *  cout << "ExceptionFunc()" << endl;  
69  *   
70  *  ExceptionFunc()The call ends, returns to main(), and proceeds downward;
71  *  cout << "test end!" << endl;
72  */
Scenario 2: Reproduction of anomaly case 1

 

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 double divide(double a, double b)
 7 {
 8     const double delta = 0.000000001;
 9     double ret = 0;
10           
11     if( !((-delta < b) && (b < delta)) )
12     {
13         ret = a / b;
14     }
15     else
16     {
17         throw "Divided by zero..."; 
18     }
19 
20     cout << "divide(double a, double b)" << endl;
21 
22     return ret;
23 }
24 
25 double ExceptionFunc()
26 {
27     double d;
28     
29     try
30     {
31         d = divide(2, 0);
32             
33         cout << "d = " << d << endl;
34     }
35     catch(char const* s)
36     {
37         cout << s << endl;
38     }           
39     
40     cout << "ExceptionFunc()" << endl;
41     
42     return d;
43 }
44 
45 int main(int argc, char *argv[])
46 { 
47     ExceptionFunc();
48     
49     cout << "test end!" << endl;
50 
51     return 0;
52 }
53 
54 /**
55  * Run result:
56  * Divided by zero...
57  * ExceptionFunc()
58  * test end!
59  */
60  
61 /**
62  * Analysis:
63  * throw "Divided by zero..."; After throwing an exception, the divide(double a, double b) function cannot catch the exception, then the exception continues to be thrown to ExceptionFunc();
64  * In ExceptionFunc(), if an exception is caught, the program proceeds downward;
65  *  catch(char const* s)    // throw "Divided by zero..."
66  *  {
67  *     cout << s << endl;
68  *  }   
69  *  cout << "ExceptionFunc()" << endl;     
70  *  ExceptionFunc()The call ends, returns to main(), and proceeds downward;
71  *  cout << "test end!" << endl;
72  */
Scenario 2: Reproduction of Abnormal List 2

 

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 double divide(double a, double b)
 7 {
 8     const double delta = 0.000000001;
 9     double ret = 0;
10 
11     if( !((-delta < b) && (b < delta)) )
12     {
13         ret = a / b;
14     }
15     else
16     {
17         throw "Divided by zero..."; 
18     }
19  
20     cout << "divide(double a, double b)" << endl;
21 
22     return ret;
23 }
24 
25 double ExceptionFunc()
26 {
27     double d = divide(2, 0);
28     
29     cout << "ExceptionFunc()" << endl;
30     
31     return d;
32 }
33 
34 int main(int argc, char *argv[])
35 { 
36     try
37     {
38         double d = ExceptionFunc();
39             
40         cout << "d = " << d << endl;
41     }
42     catch(char const* s)
43     {
44         cout << s << endl;
45     }        
46     
47     cout << "test end!" << endl;
48 
49     return 0;
50 }
51 
52 /**
53  * Run result:
54  * Divided by zero...
55  * test end!
56  */
57  
58 /**
59  * Analysis:
60  * throw "Divided by zero..."; After throwing an exception, the divide(double a, double b) function cannot catch the exception, then the exception continues to be thrown to ExceptionFunc();
61  * In ExceptionFunc(), if the exception cannot be caught, the exception continues to be thrown to main();
62  * In main(), exceptions and captures continue downward
63  *  catch(char const* s)    // throw "Divided by zero..."
64  *  {
65  *     cout << s << endl;
66  *  }   
67  *  cout << "test end!" << endl;     
68  */
Scenario 2: Reproduction of anomaly case 3

 

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 void Demo1()
 7 {
 8     try
 9     {   
10         throw 2.0;
11     }
12     catch(char c)
13     {
14         cout << "catch(char c)" << endl;
15     }
16     catch(short c)
17     {
18         cout << "catch(short c)" << endl;
19     }
20     catch(double c)   // throw 2.0;
21     {
22         cout << "catch(double c)" << endl;
23     }
24     catch(...)   // Indicates that any type of exception is caught
25     {
26         cout << "catch(...)" << endl;
27     }   
28 }
29 
30 void Demo2()
31 {
32     throw string("D.T.Software"); 
33 }
34 
35 int main(int argc, char *argv[])
36 {    
37     Demo1();
38     
39     try
40     {
41         Demo2();      
42     }
43     catch(char* s)
44     {
45         cout << "catch(char *s)" << endl;
46     }
47     catch(const char* cs)
48     {
49         cout << "catch(const char *cs)" << endl;
50     }
51     catch(string ss)    // throw string("D.T.Software"); 
52     {
53         cout << "catch(string ss)" << endl;
54     }  
55     
56     return 0;
57 }
58 /**
59  * Run result:
60  * catch(double c)
61  * catch(string ss)
62  */
63 
64 // Conclusion: The types of abnormalities match strictly, (...)Indicates that any type of exception is caught
Scenario 2: Multi-branch exception capture

Summary:

Situation 1: Only exceptions are thrown, no corresponding exception capture is made; (No try... Catch... Structure)

Situation 2: Throw an exception in the try statement block (throw throws an exception directly in the try statement block; or throw throws an exception in the try statement block; or put an exception function in the try statement block, indirectly throw throws an exception in the function), then catch the same type of exception through the catch statement and handle the exception; (Phenomenon: A try... Catch... Structure)

Now let's consider whether we can continue throwing exceptions on the basis of scenario 2.(Rethrow exception in catch statement block?)

You can re-throw an exception in a catch statement, requiring an outer try... Catch... To catch the exception;

Note: Only exceptions are thrown and nothing is done in the catch statement; when any type of exception is caught, throw is used directly.

  

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 void Demo()
 7 {
 8     try
 9     {
10         throw 'c';
11     }
12     catch(int i)
13     {
14         cout << "Inner: catch(int i)" << endl;
15         throw i;
16     }
17     catch(...)
18     {
19         cout << "Inner: catch(...)" << endl;
20         throw;
21     }
22 }
23 
24 int main(int argc, char *argv[])
25 {
26     Demo();
27     
28     return 0;
29 }
30 
31 /**
32  * Run result:
33  * Inner: catch(...)
34  * terminate called after throwing an instance of 'char'
35  * Aborted (core dumped)
36  */
37  // Error Reason: Exception was not caught after Reinterpretation
Exception reinterpretation column (error)

 

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 void Demo()
 7 {
 8     try
 9     {
10         try
11         {
12             throw 'c';
13         }
14         catch(int i)
15         {
16             cout << "Inner: catch(int i)" << endl;
17             throw i;
18         }
19         catch(...)
20         {
21             cout << "Inner: catch(...)" << endl;
22             throw;
23         }
24     }
25     catch(...)
26     {
27         cout << "Outer: catch(...)" << endl;
28     }
29 }
30 
31 int main(int argc, char *argv[])
32 {
33     Demo();
34     
35     return 0;
36 }
37 /**
38  * Run result:
39  * Inner: catch(...)
40  * Outer: catch(...)
41  */
Exception Re-Interpretation Column

Why re-throw exceptions in the catch statement block?

In engineering, you can unify exception types by reinterpreting exceptions in the catch statement block and throwing them out.(It's obscure, see the explanation below....)

  

This is illustrated in detail in the figure above:

Background: For development efficiency reasons, third-party libraries are generally used in project development. However, some functions in third-party libraries are not perfect (poor readability), so it is necessary to encapsulate this function in third-party libraries.

In the figure above, because the exception type of the func() function in the third-party library is int, the readability is poor, and the meaning of the exception cannot be known directly from the exception result; in this case, we encapsulate the func() function in the third-party library through the MyFunc() function in the private library, making theException types in MyFunc() functions can display more exception information (exception types in MyFunc() functions are custom types, which can be strings, class types, etc.) to enhance code readability; to unify exception types in func() with exception types in MyFunc(), we can capture exception types in third-party libraries in MyFunc() functions in private libraries.The exception thrown by the func() function is then reinterpreted as the one we want based on the exception captured, so that the types of exceptions we face in our project development are the same; next, we'll recreate this scenario with code:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 /*
 7     Assume: The current function is a function in a third-party library, so we cannot modify the source code
 8     
 9     Function name: void func(int i)
10     Type of exception thrown: int
11                         -1 ==> Parameter Exception
12                         -2 ==> Run Exception
13                         -3 ==> Timeout exception
14 */
15 void func(int i)
16 {
17     if( i < 0 )
18     {
19         throw -1;
20     }
21     
22     if( i > 100 )
23     {
24         throw -2;
25     }
26     
27     if( i == 11 )
28     {
29         throw -3;
30     }
31     
32     cout << "Run func..." << endl;
33 }
34 
35 int main(int argc, char *argv[])
36 {
37     try
38     {
39         func(11);
40     }
41     catch(int i)
42     {
43         cout << "Exception Info: " << i << endl;
44     }
45     
46     return 0;
47 }
48 
49 /**
50  * Run result:
51  * Exception Info: -3
52  */
53  
54 // Exception display results are too simple. When an exception occurs, you need to query the technical documentation to know what's here-3 Meaning represented, poor readability
Simulate exception code column of third party Library

 

//Re-interpret exceptions, re-throw exceptions in catch statements

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 /*
 7     Assumption: Functions in the current functional third-party library, so we cannot modify the source code
 8     
 9     Function name: void func(int i)
10     Type of exception thrown: int
11                         -1 ==> Parameter Exception
12                         -2 ==> Run Exception
13                         -3 ==> Timeout exception
14 */
15 void func(int i)
16 {
17     if( i < 0 )
18     {
19         throw -1;
20     }
21     
22     if( i > 100 )
23     {
24         throw -2;
25     }
26     
27     if( i == 11 )
28     {
29         throw -3;
30     }
31     
32     cout << "Run func..." << endl;
33 }
34 
35 /* If the func() function cannot be modified, then we define the MyFunc() function to reinterpret the func() exception */
36 void MyFunc(int i)
37 {
38     try
39     {
40         func(i);
41     }
42     catch(int i)
43     {
44         switch(i)
45         {
46             case -1:
47                 throw "Invalid Parameter";   // You can throw out more detailed data, such as class objects, for later explanation
48                 break;
49             case -2:
50                 throw "Runtime Exception";
51                 break;
52             case -3:
53                 throw "Timeout Exception";
54                 break;
55         }
56     }
57 }
58 
59 int main(int argc, char *argv[])
60 {
61     try
62     {
63         MyFunc(11);
64     }
65     catch(const char* cs)
66     {
67         cout << "Exception Info: " << cs << endl;
68     }
69     
70     return 0;
71 }
72 /**
73  * Run result:
74  * Exception Info: Timeout Exception
75  */
Simulate third-party library exception code (improved version)

 

  3. Customize how exception classes are used

(1) The type of exception can be a custom class type;

(2) The matching of class type exceptions is still top-down strict matching;

(3) The assignment compatibility principle is still applicable in exception matching; (Note: In assignment compatibility, the subclass is a special parent, and the parent can catch the exception of the subclass; the principle of strict match of exception types is also satisfied)

(4) In the Assignment Compatibility Principle, the

(1) Catches matching subclass exceptions are placed on top;

(2) Catches matching parent exceptions are placed at the bottom;

(5) When defining a catch statement block, const reference is recommended as a parameter to improve the efficiency of the program;

  1 #include <iostream>
  2 #include <string>
  3 
  4 using namespace std;
  5 
  6 class Base
  7 {
  8 };
  9 
 10 /* Define exception classes */
 11 class Exception : public Base
 12 {
 13     int m_id;
 14     string m_desc;
 15 public:
 16     Exception(int id, string desc)
 17     {
 18         m_id = id;
 19         m_desc = desc;
 20     }
 21     
 22     int id() const
 23     {
 24         return m_id;
 25     }
 26     
 27     string description() const
 28     {
 29         return m_desc;
 30     }
 31 };
 32 
 33 /*
 34     Assumption: Functions in the current functional third-party library, so we cannot modify the source code
 35     Function name: void func(int i)
 36     Type of exception thrown: int
 37                         -1 ==> Parameter Exception
 38                         -2 ==> Run Exception
 39                         -3 ==> Timeout exception
 40 */
 41 
 42 void func(int i)
 43 {
 44     if( i < 0 )
 45     {
 46         throw -1;
 47     }
 48     
 49     if( i > 100 )
 50     {
 51         throw -2;
 52     }
 53     
 54     if( i == 11 )
 55     {
 56         throw -3;
 57     }
 58     
 59     cout << "Run func..." << endl;
 60 }
 61 
 62 /* Optimize using custom class types */
 63 void MyFunc(int i)
 64 {
 65     try
 66     {
 67         func(i);
 68     }
 69     catch(int i)
 70     {
 71         switch(i)
 72         {
 73             case -1:
 74                 throw Exception(-1, "Invalid Parameter");  // Call the constructor directly to generate the exception object;
 75                 break;
 76             case -2:
 77                 throw Exception(-2, "Runtime Exception");
 78                 break;
 79             case -3:
 80                 throw Exception(-3, "Timeout Exception");
 81                 break;
 82         }
 83     }
 84 }
 85 
 86 int main(int argc, char *argv[])
 87 {
 88     try
 89     {
 90         MyFunc(11);
 91     }
 92     catch(const Exception& e)  // 1 Use const Assignment Compatibility Principle with Reference Type as Parameter 2 (see point 4)
 93     {
 94         cout << "Exception Info: " << endl;
 95         cout << "   ID: " << e.id() << endl;
 96         cout << "   Description: " << e.description() << endl;
 97     }
 98     catch(const Base& e) 
 99     {
100         cout << "catch(const Base& e)" << endl;
101     }
102     
103     return 0;
104 }
105 /**
106  * Run result:
107  * Exception Info: 
108  * ID:  -3
109  * Description: Timeout Exception
110  */
Simulate third-party library exception code (perfect version)

 

4. Exception Classes in C++ Standard Library

(1) A family of useful exception classes is provided in the C++ standard library;

(2) Exceptions in the standard libraries are derived from the exception class;

(3) The exception class has two main branches:

    1)logic_error

         2)runtime_error

(4) Exception class inheritance diagram in the standard library:

    

 1 #include <iostream>
 2 #include <string>
 3 #include <stdexcept> 
 4 #include <sstream>
 5 
 6 using namespace std;
 7 
 8 /*
 9     __FILE__  __FUNCTION__  const char[]
10     __LINE__  int
11 */
12 
13 template
14 <typename T, int N>
15 class Array
16 {
17 private:
18     T arr[N];
19 public:
20     Array();
21     T& operator[] (int index);
22     void print() const;
23 };
24 
25 template
26 <typename T, int N>
27 Array<T, N>::Array()
28 {
29     for(int i = 0; i < N; i++)
30     {
31         arr[i] = 0;
32     }
33 }
34 
35 template
36 <typename T, int N>
37 T& Array<T, N>::operator[] (int index)
38 {
39     if( (0 <= index) && (index < N) )
40     {
41         return arr[index];
42     }
43     else
44     {
45         ostringstream oss;
46         
47         throw out_of_range(string(__FILE__) + ":" + static_cast<ostringstream&>(oss << __LINE__).str() + ":" + __FUNCTION__\
48 
49                         + "\t >> exception: the index of array is out of range");  
50     }
51 }
52 
53 template
54 <typename T, int N>
55 
56 void Array<T, N>::print() const
57 {
58     for(int i = 0; i < N; i++)
59     {
60         cout << arr[i] << " ";
61     }
62     cout << endl;
63 }
64 
65 int main(int argc, char *argv[])
66 {
67     try
68     {
69         Array<int, 5> arr;
70 
71         arr.print();
72         arr[-1] = 1;    // Exception testing
73         arr.print();
74     }
75 
76     catch(const out_of_range& e)  // 1 Use const Assignment Compatibility Principle with Reference Type as Parameter 2 (see point 4)
77     {
78         cout << e.what() << endl;
79     }
80 
81     catch(...)
82     {
83         cout << "other exception ... " << endl;
84     }
85 
86     return 0;
87 }
88 
89 /**
90  * Run result:
91  * 0 0 0 0 0
92  * test.cpp:47:operator[]     >> exception: the index of array is out of range
93  */
Use of out_of_range exception class

 

  1 // template file Array.hpp Optimization
  2 #ifndef ARRAY_H
  3 #define ARRAY_H
  4 
  5 #include <stdexcept>  // Exception class header file in standard library;
  6 
  7 using namespace std;A
  8 
  9 template
 10 < typename T, int N >
 11 class Array
 12 {
 13     T m_array[N];
 14 public:
 15     int length() const;
 16     bool set(int index, T value);
 17     bool get(int index, T& value);
 18     T& operator[] (int index);
 19     T operator[] (int index) const;
 20     virtual ~Array();
 21 };
 22 
 23 template
 24 < typename T, int N >
 25 int Array<T, N>::length() const
 26 {
 27     return N;
 28 }
 29 
 30 template
 31 < typename T, int N >
 32 bool Array<T, N>::set(int index, T value)
 33 {
 34     bool ret = (0 <= index) && (index < N);
 35     
 36     if( ret )
 37     {
 38         m_array[index] = value;
 39     }
 40     
 41     return ret;
 42 }
 43 
 44 template
 45 < typename T, int N >
 46 bool Array<T, N>::get(int index, T& value)
 47 {
 48     bool ret = (0 <= index) && (index < N);
 49     
 50     if( ret )
 51     {
 52         value = m_array[index];
 53     }
 54     
 55     return ret;
 56 }
 57 
 58 template
 59 < typename T, int N >
 60 T& Array<T, N>::operator[] (int index)
 61 {
 62     if( (0 <= index) && (index < N) )
 63     {
 64         return m_array[index];  // There was no validation before index Is it legal, because validation cannot be handled;
 65     }
 66     else
 67     {
 68         throw out_of_range("T& Array<T, N>::operator[] (int index)");
 69     }
 70 }
 71 
 72 template
 73 < typename T, int N >
 74 T Array<T, N>::operator[] (int index) const
 75 {
 76     if( (0 <= index) && (index < N) )
 77     {
 78         return m_array[index];  // There was no validation before index Is it legal, because validation cannot be handled;
 79     }
 80     else
 81     {
 82         throw out_of_range("T Array<T, N>::operator[] (int index) const");
 83     }
 84 }
 85 
 86 template
 87 < typename T, int N >
 88 Array<T, N>::~Array()
 89 {
 90 
 91 }
 92 
 93 #endif
 94 
 95 //------------------------------------------------------------------
 96 
 97 // template file HeapArray.hpp Optimization
 98 
 99 #ifndef HEAPARRAY_H
100 #define HEAPARRAY_H
101 
102 #include <stdexcept>  // Add standard header file;
103 
104 using namespace std;
105 
106 template
107 < typename T >
108 class HeapArray
109 {
110 private:
111     int m_length;
112     T* m_pointer;
113     
114     HeapArray(int len);
115     HeapArray(const HeapArray<T>& obj);
116     bool construct();
117 public:
118     static HeapArray<T>* NewInstance(int length); 
119     int length() const;
120     bool get(int index, T& value);
121     bool set(int index ,T value);
122     T& operator [] (int index);
123     T operator [] (int index) const;
124     HeapArray<T>& self();
125     const HeapArray<T>& self() const;  // Consider whether member functions need to be const Function, const Functions are primarily for cosnt Object call;
126     ~HeapArray();
127 };
128 
129 template
130 < typename T >
131 HeapArray<T>::HeapArray(int len)
132 {
133     m_length = len;
134 }
135 
136 template
137 < typename T >
138 bool HeapArray<T>::construct()
139 {   
140     m_pointer = new T[m_length];
141     
142     return m_pointer != NULL;
143 }
144 
145 template
146 < typename T >
147 HeapArray<T>* HeapArray<T>::NewInstance(int length) 
148 {
149     HeapArray<T>* ret = new HeapArray<T>(length);
150     
151     if( !(ret && ret->construct()) ) 
152     {
153         delete ret;
154         ret = 0;
155     }
156         
157     return ret;
158 }
159 
160 template
161 < typename T >
162 int HeapArray<T>::length() const
163 {
164     return m_length;
165 }
166 
167 template
168 < typename T >
169 bool HeapArray<T>::get(int index, T& value)
170 {
171     bool ret = (0 <= index) && (index < length());
172     
173     if( ret )
174     {
175         value = m_pointer[index];
176     }
177     
178     return ret;
179 }
180 
181 template
182 < typename T >
183 bool HeapArray<T>::set(int index, T value)
184 {
185     bool ret = (0 <= index) && (index < length());
186     
187     if( ret )
188     {
189         m_pointer[index] = value;
190     }
191     
192     return ret;
193 }
194 
195 template
196 < typename T >
197 T& HeapArray<T>::operator [] (int index)
198 {
199     if( (0 <= index) && (index < length()) )
200     {
201         return m_pointer[index];  // Optimize here, throw an exception out of bounds;
202     }
203     else
204     {
205         throw out_of_range("T& HeapArray<T>::operator [] (int index)");
206     }
207 }
208 
209 template
210 < typename T >
211 T HeapArray<T>::operator [] (int index) const
212 {
213     if( (0 <= index) && (index < length()) )
214     {
215         return m_pointer[index];  // Optimize here, throw an exception out of bounds;
216     }
217     else
218     {
219         throw out_of_range("T HeapArray<T>::operator [] (int index) const");
220     }
221 }
222 
223 template
224 < typename T >
225 HeapArray<T>& HeapArray<T>::self()
226 {
227     return *this;
228 }
229 
230 template
231 < typename T >
232 const HeapArray<T>& HeapArray<T>::self() const
233 {
234     return *this;
235 }
236 
237 template
238 < typename T >
239 HeapArray<T>::~HeapArray()
240 {
241     delete[]m_pointer;
242 }
243 
244 #endif
245 
246 //------------------------------------------------------------------
247 
248 // Test File main.cpp 
249 
250 #include <iostream>
251 #include <string>
252 #include <memory>  //for auto_ptr
253 #include "Array.hpp"
254 #include "HeapArray.hpp"
255 
256 using namespace std;
257 
258 void TestArray()
259 {
260     Array<int, 5> a;
261     
262     for(int i=0; i<a.length(); i++)
263     {
264         a[i] = i;   
265     }
266     
267     for (int i=0; i<a.length(); i++)
268     {
269         cout << a[i] << ", ";
270     }
271     cout << endl;
272 }
273 
274 void TestHeapArray()
275 {
276     //Use smart pointers to automatically free heap space
277     auto_ptr< HeapArray<double> > pa(HeapArray<double>::NewInstance(5));
278     
279     if(pa.get() != NULL)
280     {
281         HeapArray<double>& array = pa->self();
282         
283         for(int i=0; i<array.length(); i++)
284         {
285             array[i] = i;
286         }
287         
288         for (int i=0; i<array.length(); i++)
289         {
290              cout << array[i] << ", ";
291         }
292         cout << endl;         
293     }         
294 }
295 
296 int main(int argc, char *argv[])
297 {
298     try
299     {
300         TestArray();
301 
302         cout << endl;     
303 
304         TestHeapArray();
305     }
306     catch(const out_of_range& e)
307     {
308         cout << "exception: " << e.what() << endl;
309     }
310     catch(...)
311     {
312         cout << "other exception ... " << endl;
313     }   
314 
315     return 0;
316 }
317 
318 /**
319  * Ship new results:
320  * 0, 1, 2, 3, 4, 
321  * ---------------------
322  * 0, 1, 2, 3, 4, 
323  * Run End...
324  */
325 
326 /**
327  * Stack space array subscript out of bounds exception results:
328  * exception: T& Array<T, N>::operator[] (int index)
329  * Run End...
330  */
331 
332 /**
333  * Heap space array subscript out of bounds exception results:
334  * 0, 1, 2, 3, 4, 
335  * ---------------------
336  * exception: T& HeapArray<T>::operator [] (int index)
337  * Run End...
338  */
Array subscript crossover exception column in standard library

 

5. try..catch alternative writing and function exception declaration/definition throw()

The features of try..catch alternative writing (not recommended):

(1) try-catch is used to separate normal function code from exception handling code

(2) try-catch separates function implementations directly into two parts

Features of function exception declaration/definition:

(1) When a function is declared and defined, the exception type that may be thrown can be specified directly;

(2) Exception declarations become part of functions and improve code readability;

(3) A function exception declaration is a contract with the compiler;

(4) When a function declares an exception, only the declared exception can be thrown;

A. Throwing other exceptions will cause the program to terminate;

(B) The function without exception can be defined directly by exception declaration;

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 // int func(int i, int j) throw()  // No exception function declaration
 7 
 8 int func(int i, int j) throw(int, char)  //Exception declaration indicating that the function may throw int and char Two types of exceptions
 9 {
10     if ((0 < j) && (j < 10))
11     {
12         return (i + j);
13     } 
14     else
15     {
16         throw 'c'; // Only the specified exception type can be thrown ( int,char),Otherwise, the program fails to run
17     }
18 }
19 
20 //The following is no longer recommended  !!!
21 void test(int i) try   //Normal Code
22 {
23     cout << "func(i, i) = " << func(i, i) << endl;
24 }
25 catch (int j)   //Exception Code
26 {
27     cout << "Exception: " << j << endl;
28 }
29 catch (char j)   //Exception Code
30 {
31     cout << "Exception: " << j << endl;
32 }
33 
34 int main(int argc, char *argv[])
35 {
36     test(5); //normal
37 
38     test(10); //Throw an exception
39 
40     return 0;
41 }
42 /**
43  * Run result:
44  * func(i, i) = 10
45  * Exception: c
46  */
Alternative writing of try..catch + throw declaration exception type

  

Tags: C++

Posted on Sat, 21 Mar 2020 13:01:40 -0400 by kitaeshi