Exception Handling
Exceptions provide a way to react to exceptional circumstances (like runtime errors) in our program by transferring control to special functions called handlers.
C++ exception handling is built upon three keywords: try, catch, and throw.
throw: A program throws an exception when a problem shows up. This is done using a throw keyword.
catch: A program catches an exception with an exception handler at the place in a program where you want to handle the problem. The catch keyword indicates the catching of an exception.
try: A try block identifies a block of code for which particular exceptions will be activated. It's followed by one or more catch blocks.
Assuming a block will raise an exception, a method catches an exception using a combination of the try and catch keywords. A try/catch block is placed around the code that might generate an exception. Code within a try/catch block is referred to as protected code, and the syntax for using try/catch looks like the following:
try
{
// protected code
}catch( ExceptionName e1 )
{
// catch block
}catch( ExceptionName e2 )
{
// catch block
}catch( ExceptionName eN )
{
// catch block
}
You can list down multiple catch statements to catch different type of exceptions in case your try block raises more than one exception in different situations.
Throwing Exception
Exceptions can be thrown anywhere within a code block using throw statements. The operand of the throw statements determines a type for the exception and can be any expression and the type of the result of the expression determines the type of exception thrown.
Following is an example of throwing an exception when dividing by zero condition occurs:
double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
Catching Exceptions
The catch block following the try block catches any exception. You can specify what type of exception you want to catch and this is determined by the exception declaration that appears in parentheses following the keyword catch.
try
{
// protected code
}catch( ExceptionName e )
{
// code to handle ExceptionName exception
}
C++ Standard Exceptions
std::exception - An exception and parent class of all the standard C++ exceptions.
std::bad_alloc - This can be thrown by new.
std::bad_cast - This can be thrown by dynamic_cast.
std::bad_exception - This is useful device to handle unexpected exceptions in a C++ program
std::bad_typeid - This can be thrown by typeid.
std::logic_error - An exception that theoretically can be detected by reading the code.
std::domain_error - This is an exception thrown when a mathematically invalid domain is used
std::invalid_argument - This is thrown due to invalid arguments.
std::length_error - This is thrown when a too big std::string is created
std::out_of_range - This can be thrown by the at method from for example a std::vector and std::bitset < >::operator[]().
std::runtime_error - An exception that theoretically can not be detected by reading the code.
std::overflow_error - This is thrown if a mathematical overflow occurs.
std::range_error - This is occured when you try to store a value which is out of range.
std::underflow_error - This is thrown if a mathematical underflow occurs.
Define your own exceptions
You can define your own exceptions by inheriting and overriding exception class functionality.
eg.
struct MyException : public exception
{
const char * display() const throw ()
{
return "This is Exception";
}
};
Here, what() is a public method provided by exception class and it has been overridden by all the child exception classes. This returns the cause of an exception.
Dynamic Memory
Allocating memory
There are two ways that memory gets allocated for data storage:
Compile Time (or static) Allocation
- Memory for named variables is allocated by the compiler
- Exact size and type of storage must be known at compile time
- For standard array declarations, this is why the size has to be constant
Dynamic Memory Allocation
- Memory allocated "on the fly" during run time
- dynamically allocated space usually placed in a program segment known as the heap or the free store.
- Exact amount of space or number of items does not have to be known by the compiler in advance.
- For dynamic memory allocation, pointers are crucial.
Dynamic Memory Allocation
We can dynamically allocate storage space while the program is running, but we cannot create new variable names "on the fly"
For this reason, dynamic allocation requires two steps:
- Creating the dynamic space.
- Storing its address in a pointer (so that the space can be accesed)
To dynamically allocate memory in C++, we use the new operator.
De-allocation:
- Deallocation is the "clean-up" of space being used for variables or other data storage
- Compile time variables are automatically deallocated based on their known extent (this is the same as scope for "automatic" variables)
- It is the programmer's job to deallocate dynamically created space
- To de-allocate dynamic memory, we use the delete operator
Allocating space with new
To allocate space dynamically, use the unary operator new, followed by the type being allocated.
new int;
//dynamically allocate an int
new double;
//dynamically allocates a double
If creating an array dynamically, use the same form, but put brackets with a size after the type:
new int[40];
//dynamically allocates an arrat of 40 ints
new doube[size];
//dynamically allocates an array of size doubles
These statements above are not very useful by themselves, because the allocated spaces have no names! BUT, the new operator returns the starting address of the allocated space, and this address can be stored in a pointer:
int * p;
// declare a pointer p
p = new int;
// dynamically allocate an int and load address into p
Deallocation of dynamic memory
To deallocate memory that was created with new, we use the unary operator delete. The one operand should be a pointer that stores the address of the space to be deallocated:
int * ptr = new int;
// dynamically created int
...
delete ptr;
// deletes the space that ptr points to
Note that the pointer ptr still exists in this example. That's a named variable subject to scope and extent determined at compile time. It can be reused:
ptr = new int[10];
// point p to a brand new array
To deallocate a dynamic array, use this form:
delete [] name_of_pointer;
10.3 Templates
Templates in C++ programming allows function or class to work on more than one data type at once without writing different codes for different data types. Templates are often used in larger programs for the purpose of code reusability and flexibility of program. The concept of templetes can be used in two different ways:
- Function Template
- Class Template
Function Template
A function templates work in similar manner as function but with one key difference. A single function template can work on different types at once but, different functions are needed to perform identical task on different data types.
The general form of a template function definition is shown here:
template <class type> ret-type func-name(parameter list)
{
// body of function
}
Here, type is a placeholder name for a data type used by the function. This name can be used within the function definition.
Class Template
Just as we can define function templates, we can also define class templates. The general form of a generic class declaration is shown here:
template <class type> class class-name {
.
.
.
}
Here, type is the placeholder type name, which will be specified when a class is instantiated. You can define more than one generic data type by using a comma-separated list.
10.4 Preprocessor
The preprocessors are the directives, which give instruction to the compiler to preprocess the information before actual compilation starts.
All preprocessor directives begin with #, and only white-space characters may appear before a preprocessor directive on a line. Preprocessor directives are not C++ statements, so they do not end in a semicolon (;). We already know #include directive.
Different preprocessor directives (commands) perform different tasks. We can categorize the Preprocessor Directives as follows:
- Inclusion Directives - Macro Definition Directives - Conditional Compilation Directives Inclusion Directive
This category has only one directive, which is called #include. This inclusion directive is used to include files into the current file. The inclusion directive can be used as follows:
#include <stdio.h>
includes stdio.h from include folder
#include<iostream>
includes cpp class library header iostream
#include<my.cpp>
includes my.cpp file from include folder
#include ''my.h''
includes my.h file from current working folder
Macro Definition Directives
These are used to define macros, which are one, or more program statements (like functions) and they are expanded inline.
There are two directives for Macro Definition:
#define - Used to define a macro
#undef - Used to undefine a macro (The macro cannot be used after it is undefined.)
Conditional Compilation Directives
Conditional Compilation Directives these are used to execute statements conditionally for:
- Executing the code on different machine architectures.
- Debugging purposes.
- Macros can be dependent on other macros (must be defined before they are used.)
- Evaluating codes, which are to be executed depending upon the requirements of the programmer.
The following directives are included in this category:
#if
#elif
#endif
#ifdef
#ifndef
Note: These macros are evaluated on compile time. Therefore they can only use the predefined macros or literals. Most compilers do not support the use of variables with these directives.
Download for more knowledge
https://play.google.com/store/apps/details?id=cpp.programming
Comments
Post a Comment