
So far, we have been using the iostream standard library, which provides cin and cout methods for reading from standard input and wr...
Everything is in this blog
So far, we have been using the iostream standard library, which provides cin and cout methods for reading from standard input and wr...
An exception is a problem that arises during the execution of a program. A C++ exception is a response to an exceptional circumstance ...
A good understanding of how dynamic memory really works in C++ is essential to becoming a good C++ programmer. Memory in your C++ prog...
Consider a situation, when we have two persons with the same name, Zara, in the same class. Whenever we need to differentiate them d...
Templates are the foundation of generic programming, which involves writing code in a way that is independent of any particular type. ...
The preprocessors are the directives, which give instruction to the compiler to preprocess the information before actual compilation s...
Signals are the interrupts delivered to a process by the operating system which can terminate a program prematurely. You can generate i...
Replace these every slider sentences with your featured post descriptions.Go to Blogger edit html and find these sentences.Now replace these with your own descriptions.
Replace these every slider sentences with your featured post descriptions.Go to Blogger edit html and find these sentences.Now replace these with your own descriptions.
Replace these every slider sentences with your featured post descriptions.Go to Blogger edit html and find these sentences.Now replace these with your own descriptions.
Data Type | Description |
---|---|
ofstream | This data type represents the output file stream and is used to create files and to write information to files. |
ifstream | This data type represents the input file stream and is used to read information from files. |
fstream | This data type represents the file stream generally, and has the capabilities of both ofstream and ifstream which means it can create files, write information to files, and read information from files. |
void open(const char *filename, ios::openmode mode);Here, the first argument specifies the name and location of the file to be opened and the second argument of the open() member function defines the mode in which the file should be opened.
Mode Flag | Description |
---|---|
ios::app | Append mode. All output to that file to be appended to the end. |
ios::ate | Open a file for output and move the read/write control to the end of the file. |
ios::in | Open a file for reading. |
ios::out | Open a file for writing. |
ios::trunc | If the file already exists, its contents will be truncated before opening the file. |
ofstream outfile; outfile.open("file.dat", ios::out | ios::trunc );Similar way, you can open a file for reading and writing purpose as follows:
fstream afile; afile.open("file.dat", ios::out | ios::in );
void close();
#include <fstream> #include <iostream> using namespace std; int main () { char data[100]; // open a file in write mode. ofstream outfile; outfile.open("afile.dat"); cout << "Writing to the file" << endl; cout << "Enter your name: "; cin.getline(data, 100); // write inputted data into the file. outfile << data << endl; cout << "Enter your age: "; cin >> data; cin.ignore(); // again write inputted data into the file. outfile << data << endl; // close the opened file. outfile.close(); // open a file in read mode. ifstream infile; infile.open("afile.dat"); cout << "Reading from the file" << endl; infile >> data; // write the data at the screen. cout << data << endl; // again read the data from the file and display it. infile >> data; cout << data << endl; // close the opened file. infile.close(); return 0; }When the above code is compiled and executed, it produces the following sample input and output:
$./a.out Writing to the file Enter your name: Zara Enter your age: 9 Reading from the file Zara 9Above examples make use of additional functions from cin object, like getline() function to read the line from outside and ignore() function to ignore the extra characters left by previous read statement.
// position to the nth byte of fileObject (assumes ios::beg) fileObject.seekg( n ); // position n bytes forward in fileObject fileObject.seekg( n, ios::cur ); // position n bytes back from end of fileObject fileObject.seekg( n, ios::end ); // position at end of fileObject fileObject.seekg( 0, ios::end );
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.
double division(int a, int b) { if( b == 0 ) { throw "Division by zero condition!"; } return (a/b); }
try { // protected code }catch( ExceptionName e ) { // code to handle ExceptionName exception }Above code will catch an exception of ExceptionName type. If you want to specify that a catch block should handle any type of exception that is thrown in a try block, you must put an ellipsis, ..., between the parentheses enclosing the exception declaration as follows:
try { // protected code }catch(...) { // code to handle any exception }The following is an example, which throws a division by zero exception and we catch it in catch block.
#include <iostream> using namespace std; double division(int a, int b) { if( b == 0 ) { throw "Division by zero condition!"; } return (a/b); } int main () { int x = 50; int y = 0; double z = 0; try { z = division(x, y); cout << z << endl; }catch (const char* msg) { cerr << msg << endl; } return 0; }Because we are raising an exception of type const char*, so while catching this exception, we have to use const char* in catch block. If we compile and run above code, this would produce the following result:
Division by zero condition!
Exception | Description |
---|---|
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. |
#include <iostream> #include <exception> using namespace std; struct MyException : public exception { const char * what () const throw () { return "C++ Exception"; } }; int main() { try { throw MyException(); } catch(MyException& e) { std::cout << "MyException caught" << std::endl; std::cout << e.what() << std::endl; } catch(std::exception& e) { //Other errors } }This would produce the following result:
MyException caught C++ ExceptionHere, 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.
new data-type;Here, data-type could be any built-in data type including an array or any user defined data types include class or structure. Let us start with built-in data types. For example we can define a pointer to type double and then request that the memory be allocated at execution time. We can do this using the new operator with the following statements:
double* pvalue = NULL; // Pointer initialized with null pvalue = new double; // Request memory for the variableThe memory may not have been allocated successfully, if the free store had been used up. So it is good practice to check if new operator is returning NULL pointer and take appropriate action as below:
double* pvalue = NULL; if( !(pvalue = new double )) { cout << "Error: out of memory." <<endl; exit(1); }The malloc() function from C, still exists in C++, but it is recommended to avoid using malloc() function. The main advantage of new over malloc() is that new doesn't just allocate memory, it constructs objects which is prime purpose of C++.
delete pvalue; // Release memory pointed to by pvalueLet us put above concepts and form the following example to show how new and delete work:
#include <iostream> using namespace std; int main () { double* pvalue = NULL; // Pointer initialized with null pvalue = new double; // Request memory for the variable *pvalue = 29494.99; // Store value at allocated address cout << "Value of pvalue : " << *pvalue << endl; delete pvalue; // free up the memory. return 0; }If we compile and run above code, this would produce the following result:
Value of pvalue : 29495
char* pvalue = NULL; // Pointer initialized with null pvalue = new char[20]; // Request memory for the variableTo remove the array that we have just created the statement would look like this:
delete [] pvalue; // Delete array pointed to by pvalueFollowing the similar generic syntax of new operator, you can allocat for a multi-dimensional array as follows:
double** pvalue = NULL; // Pointer initialized with null pvalue = new double [3][4]; // Allocate memory for a 3x4 arrayHowever, the syntax to release the memory for multi-dimensional array will still remain same as above:
delete [] pvalue; // Delete array pointed to by pvalue
#include <iostream> using namespace std; class Box { public: Box() { cout << "Constructor called!" <<endl; } ~Box() { cout << "Destructor called!" <<endl; } }; int main( ) { Box* myBoxArray = new Box[4]; delete [] myBoxArray; // Delete array return 0; }If you were to allocate an array of four Box objects, the Simple constructor would be called four times and similarly while deleting these objects, destructor will also be called same number of times.
Constructor called! Constructor called! Constructor called! Constructor called! Destructor called! Destructor called! Destructor called! Destructor called!
namespace namespace_name { // code declarations }To call the namespace-enabled version of either function or variable, prepend the namespace name as follows:
name::code; // code could be variable or function.Let us see how namespace scope the entities including variable and functions:
#include <iostream> using namespace std; // first name space namespace first_space{ void func(){ cout << "Inside first_space" << endl; } } // second name space namespace second_space{ void func(){ cout << "Inside second_space" << endl; } } int main () { // Calls function from first name space. first_space::func(); // Calls function from second name space. second_space::func(); return 0; }If we compile and run above code, this would produce the following result:
Inside first_space Inside second_space
#include <iostream> using namespace std; // first name space namespace first_space{ void func(){ cout << "Inside first_space" << endl; } } // second name space namespace second_space{ void func(){ cout << "Inside second_space" << endl; } } using namespace first_space; int main () { // This calls function from first name space. func(); return 0; }If we compile and run above code, this would produce the following result:
Inside first_spaceThe using directive can also be used to refer to a particular item within a namespace. For example, if the only part of the std namespace that you intend to use is cout, you can refer to it as follows:
using std::cout;Subsequent code can refer to cout without prepending the namespace, but other items in the std namespace will still need to be explicit as follows:
#include <iostream> using std::cout; int main () { cout << "std::endl is used with std!" << std::endl; return 0; }If we compile and run above code, this would produce the following result:
std::endl is used with std!Names introduced in a using directive obey normal scope rules. The name is visible from the point of the using directive to the end of the scope in which the directive is found. Entities with the same name defined in an outer scope are hidden.
namespace namespace_name { // code declarations }
namespace namespace_name1 { // code declarations namespace namespace_name2 { // code declarations } }You can access members of nested namespace by using resultion operators as follows:
// to access members of namespace_name2 using namespace namespace_name1::namespace_name2; // to access members of namespace:name1 using namespace namespace_name1;In the above statements if you are using namespace_name1, then it will make elements of namespace_name2 available in the scope as follows:
#include <iostream> using namespace std; // first name space namespace first_space{ void func(){ cout << "Inside first_space" << endl; } // second name space namespace second_space{ void func(){ cout << "Inside second_space" << endl; } } } using namespace first_space::second_space; int main () { // This calls function from second name space. func(); return 0; }If we compile and run above code, this would produce the following result:
Inside second_space
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.
#include <iostream> #include <string> using namespace std; template <typename T> inline T const& Max (T const& a, T const& b) { return a < b ? b:a; } int main () { int i = 39; int j = 20; cout << "Max(i, j): " << Max(i, j) << endl; double f1 = 13.5; double f2 = 20.7; cout << "Max(f1, f2): " << Max(f1, f2) << endl; string s1 = "Hello"; string s2 = "World"; cout << "Max(s1, s2): " << Max(s1, s2) << endl; return 0; }If we compile and run above code, this would produce the following result:
Max(i, j): 39 Max(f1, f2): 20.7 Max(s1, s2): World
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.
#include <iostream> #include <vector> #include <cstdlib> #include <string> #include <stdexcept> using namespace std; template <class T> class Stack { private: vector<T> elems; // elements public: void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const{ // return true if empty. return elems.empty(); } }; template <class T> void Stack<T>::push (T const& elem) { // append copy of passed element elems.push_back(elem); } template <class T> void Stack<T>::pop () { if (elems.empty()) { throw out_of_range("Stack<>::pop(): empty stack"); } // remove last element elems.pop_back(); } template <class T> T Stack<T>::top () const { if (elems.empty()) { throw out_of_range("Stack<>::top(): empty stack"); } // return copy of last element return elems.back(); } int main() { try { Stack<int> intStack; // stack of ints Stack<string> stringStack; // stack of strings // manipulate int stack intStack.push(7); cout << intStack.top() <<endl; // manipulate string stack stringStack.push("hello"); cout << stringStack.top() << std::endl; stringStack.pop(); stringStack.pop(); } catch (exception const& ex) { cerr << "Exception: " << ex.what() <<endl; return -1; } }If we compile and run above code, this would produce the following result:
7 hello Exception: Stack<>::pop(): empty stack
#define macro-name replacement-textWhen this line appears in a file, all subsequent occurrences of macro in that file will be replaced by replacement-text before the program is compiled. For example:
#include <iostream> using namespace std; #define PI 3.14159 int main () { cout << "Value of PI :" << PI << endl; return 0; }Now, let us do the preprocessing of this code to see the result, assume we have source code file, so let us compile it with -E option and redirect the result to test.p. Now, if you will check test.p, it will have lots of information and at the bottom, you will fine the value replaced as follows:
$gcc -E test.cpp > test.p ... int main () { cout << "Value of PI :" << 3.14159 << endl; return 0; }
#include <iostream> using namespace std; #define MIN(a,b) (((a)<(b)) ? a : b) int main () { int i, j; i = 100; j = 30; cout <<"The minimum is " << MIN(i, j) << endl; return 0; }If we compile and run above code, this would produce the following result:
The minimum is 30
#ifndef NULL #define NULL 0 #endifYou can compile a program for debugging purpose and can debugging turn on or off using a single macro as follows:
#ifdef DEBUG cerr <<"Variable x = " << x << endl; #endifcauses the cerr statement to be compiled in the program if the symbolic constant DEBUG has been defined before directive #ifdef DEBUG. You can use #if 0 statment to comment out a portion of the program as follows:
#if 0 code prevented from compiling #endifLet us try the following example:
#include <iostream> using namespace std; #define DEBUG #define MIN(a,b) (((a)<(b)) ? a : b) int main () { int i, j; i = 100; j = 30; #ifdef DEBUG cerr <<"Trace: Inside main function" << endl; #endif #if 0 /* This is commented part */ cout << MKSTR(HELLO C++) << endl; #endif cout <<"The minimum is " << MIN(i, j) << endl; #ifdef DEBUG cerr <<"Trace: Coming out of main function" << endl; #endif return 0; }If we compile and run above code, this would produce the following result:
Trace: Inside main function The minimum is 30 Trace: Coming out of main function
#include <iostream> using namespace std; #define MKSTR( x ) #x int main () { cout << MKSTR(HELLO C++) << endl; return 0; }If we compile and run above code, this would produce the following result:
HELLO C++Let us see how it worked. It is simple to understand that the C++ preprocessor turns the line:
cout << MKSTR(HELLO C++) << endl;into the following line:
cout << "HELLO C++" << endl;The ## operator is used to concatenate two tokens. Here is an example:
#define CONCAT( x, y ) x ## yWhen CONCAT appears in the program, its arguments are concatenated and used to replace the macro. For example, CONCAT(HELLO, C++) is replaced by "HELLO C++" in the program as follows.
#include <iostream> using namespace std; #define concat(a, b) a ## b int main() { int xy = 100; cout << concat(x, y); return 0; }If we compile and run above code, this would produce the following result:
100
Let us see how it worked. It is simple to understand that the C++ preprocessor transforms:cout << concat(x, y);into the following line:
cout << xy;
Macro | Description |
---|---|
__LINE__ | This contain the current line number of the program when it is being compiled. |
__FILE__ | This contain the current file name of the program when it is being compiled. |
__DATE__ | This contains a string of the form month/day/year that is the date of the translation of the source file into object code. |
__TIME__ | This contains a string of the form hour:minute:second that is the time at which the program was compiled. |
#include <iostream> using namespace std; int main () { cout << "Value of __LINE__ : " << __LINE__ << endl; cout << "Value of __FILE__ : " << __FILE__ << endl; cout << "Value of __DATE__ : " << __DATE__ << endl; cout << "Value of __TIME__ : " << __TIME__ << endl; return 0; }If we compile and run above code, this would produce the following result:
Value of __LINE__ : 6 Value of __FILE__ : test.cpp Value of __DATE__ : Feb 28 2011 Value of __TIME__ : 18:52:48
Signal | Description |
---|---|
SIGABRT | Abnormal termination of the program, such as a call to abort |
SIGFPE | An erroneous arithmetic operation, such as a divide by zero or an operation resulting in overflow. |
SIGILL | Detection of an illegal instruction |
SIGINT | Receipt of an interactive attention signal. |
SIGSEGV | An invalid access to storage. |
SIGTERM | A termination request sent to the program. |
void (*signal (int sig, void (*func)(int)))(int);Keeping it simple, this function receives two arguments: first argument as an integer which represents signal number and second argument as a pointer to the signal-handling function.
#include <iostream> #include <csignal> using namespace std; void signalHandler( int signum ) { cout << "Interrupt signal (" << signum << ") received.\n"; // cleanup and close up stuff here // terminate program exit(signum); } int main () { // register signal SIGINT and signal handler signal(SIGINT, signalHandler); while(1){ cout << "Going to sleep...." << endl; sleep(1); } return 0; }When the above code is compiled and executed, it produces the following result:
Going to sleep.... Going to sleep.... Going to sleep....Now, press Ctrl+c to interrupt the program and you will see that your program will catch the signal and would come out by printing something as follows:
Going to sleep.... Going to sleep.... Going to sleep.... Interrupt signal (2) received.
int raise (signal sig);Here, sig is the signal number to send any of the signals: SIGINT, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM, SIGHUP. Following is the example where we raise a signal internally using raise() function as follows:
#include <iostream> #include <csignal> using namespace std; void signalHandler( int signum ) { cout << "Interrupt signal (" << signum << ") received.\n"; // cleanup and close up stuff here // terminate program exit(signum); } int main () { int i = 0; // register signal SIGINT and signal handler signal(SIGINT, signalHandler); while(++i){ cout << "Going to sleep...." << endl; if( i == 3 ){ raise( SIGINT); } sleep(1); } return 0; }When the above code is compiled and executed, it produces the following result and would come out automatically:
Going to sleep.... Going to sleep.... Going to sleep.... Interrupt signal (2) received.