Advanced C++ topics
Do not miss this exclusive book on Binary Tree Problems. Get it now for free.
In this article, we will discuss different advanced C++ topics with a brief description along with C++ code examples.
The C++ language is an object-oriented programming language. It was developed by Dennis Ritchie at the BELL Laboratory AT & T.C++ was initially known as "C with classes" and in 1983 it was renamed as 'C'. Still now it has version as C++ 98 ,C++03,C++11,C++14,C++17,C++20. In every version of C++ ,new topic and feature were added.
Here is a list of different Advanced C++ topics we are going to understand in detail.
- RALL
- Null Pointer
- R-value and move semantics
- Smart pointers
- lambda expression
- Casting
- Run Time Type Information
- Memory leak
- kbhit
- Type Erasure
- Virtual Constructor
- stack unwinding
- Vtable
- constexpr
- Containers and algorithm
- Raw String
- Dynamic memory allocation
- decltype
- CHAR_BIT
- Uniform initialization
Now , Lets undertsand this topic in details.
1. RALL
In C++, RAII stands for " Resource Acquisition Is Initialization ". Also known as "Scope-Bound Resource Management”. It is an approach for managing the lifespan of resources.
RAII is a class variation that is associated with the life of the object. Whenever you initialize an object, it should already acquire resources using the constructor and when an object goes out of scope, it should release every acquired resource with the help of a destructor.
Additionally, it never raises an exception.
Program Code
//c program to implement RALL approach
#include <cstdio>
// exceptions
class file_error { } ;
class open_error : public file_error { } ;
class close_error : public file_error { } ;
class write_error : public file_error { } ;
//create class
class file
{
public:
file( const char* filename )
:
m_file_handle(std::fopen(filename, "w+"))
{
//check file is present or not
if( m_file_handle == NULL )
{
//throw exception
throw open_error() ;
}
}
//constructor
~file()
{
std::fclose(m_file_handle) ;
}
void write( const char* str )
{
if( std::fputs(str, m_file_handle) == EOF )
{
throw write_error() ;
}
}
void write( const char* buffer, std::size_t num_chars )
{
if( num_chars != 0 && std::fwrite(buffer, num_chars, 1, m_file_handle) == 0 )
{
throw write_error() ;
}
}
private:
std::FILE* m_file_handle ;
file( const file & ) ;
file & operator=( const file & ) ;
} ;
void example()
{
file logfile("sample.txt") ;
logfile.write("Hello World!") ;
}
Output :
Hello World
Explanation
Here ,when sample.txt file opens it allocate resouce and write data inside file and automatically get closed because file destructor is called when function returns or throws an exception
2 .Null pointer
A pointer having NULL value is called a null pointer. The standard libraries iostream and others define the NULL pointer as a constant with a value of zero.
NULL Pointer is used for following situation:
- To initialize pointers
- To represent cases like the end of an unknowable-length list
- To detect mistakes when a function returns a pointer.
A null pointer constant can have any of the following values specified:
- 0
- NULL
- C++11 nullptr
Program Code
1. #include <iostream>
2. using namespace std;
3. int main ()
4. {
5. int *ptr = NULL;
6. cout << "The value of ptr is " << ptr ;
7. return 0;
8. }
Output
The value of ptr is 0
Explanation
It print NULL Pointer value which is 0.
3. R-value and move semantics
An object's memory address is referred to as its "l-value," while a memory address's data value is referred to as its "R-value."
In C++, references are just an alternative to a variable that already exists. They are declared by adding a "&" before the variable's name. Semantics and R-value references are handled by the constructors.
Move semantics refers to pointing to an existing object in memory.In C++ ,move semantics is a set of semantic tools and rules.Instead of copying things, it was made to move objects whose lifetimes have expired. Here , Data is passed from one object to the next. Most of the time, the data transfer does not physically move the data in memory.
Program Code
1. #include <iostream>
2. void f(int& i) { std::cout << "L Value : " << i << "\n"; }
3. void f(int&& i) { std::cout << "R Value : " << i << "\n"; }
4. int main()
5. {
6. int i = 77;
7. // lvalue ref called
8. f(i);
9. // rvalue ref called
10. f(99);
11. // rvalue ref called
12. f(std::move(i));
13. return 0;
14. }
Output
L Value : 77
R Value : 99
R Value : 77
Explanation
It print L-Value and R-Value respecityviely.
4. Smart pointers
The Standard Library in modern C++ programming includes smart pointers, which are used to assist ensure that programs are free of memory and resource leaks and are exception-safe. Additionally, C++ already has built-in smart pointers it contains weak _ptr ,auto_ptr ,shared_ptr,unique _ptr.
For memory management activities like handling files, network sockets, etc., smart pointers are utilized. Additionally, it is capable of carrying out several operations, including reference counting and automatic destruction.
Program Code
#include <iostream>
using namespace std;
template <class T>
class Smartpointer
{
//Actual pointer
T *p;
public:
// Constructor of class
Smartpointer(T *ptr = NULL)
{
p = ptr;
}
// Destructor of class
~Smartpointer()
{
delete(p);
}
// Overloading de-referencing operator
T & operator * ()
{
return *p;
}
// Over loading arrow operator
T * operator -> ()
{
return p;
}
};
int main()
{
Smartpointer<int> p(new int());
*p = 10;
cout << "Pointer Value : "<<*p;
return 0;
}
Output :
Pointer Value : 10
Explanation
In this example, we have implemeted smartponter class with templeate class that includes a destructor, pointer, and overloaded operators like * and ->.The dynamically allocated memory would automatically be destroyed because the destructor is automatically invoked when an object exits scope. and the value of pointer get printed .
5. lambda expression
The lambda expression was introduced in C++ 11 ,which allows us to write an inline function for small pieces of code that will not be reused. It is known as an anonymous function object. Lambdas are used to wrap a few lines of code before passing them to asynchronous functions or algorithms.It can produce another lambda expression as its return value.
Program Code
1. #include <iostream>
2. using namespace std;
3. int main() {
4. auto greet = []()
5. {
6. cout << "Hello World!";
7. };
8. // call function
9. greet();
10. return 0;
11. }
Output
Hello World!
Explanation
In this example, we have created a lambda function that prints "Hello World!"
6. Casting
Casting is a data conversion technique . It converts data from one type to another. There are four types of casting operators in C++. Static _cast, reinterpret_cast, const_cast, and dynamic _cast are all options.
C++ has two types of conversions:
- Implicit conversion:
The compiler does implicit conversions without the assistance of the programmer. - Explicit conversion
Explicit conversions are only performed when the programmer specifically specifies them.
Program Code
1. #include <iostream>
2. using namespace std;
3. main()
4. {
5. double a = 21.09399;
6. int b ;
7. b = (int) a;
8. //type cast
9. cout << "Value of a is :" << a << endl ;
10. cout << "Value of a in integer form :" << b << endl ;
11. return 0;
12. }
Output
Value of a is : 21.09399
Value of a in integer form : 21
Explanation
In this example, we have type-cast a double value into an integer and printed the result.
7. Run Time Type Information
Run-time type information is known as RTTI. It makes it possible to identify an object's type during program excution.
Run-time type information (RTTI) is a system that determines the type of an object during program execution.
It is divided into three type as follwos
•The dynamic_cast operator :convert into polymorphic types.
•The typeid operator : determine the exact type of an item.
•The type_info class : store the data returned by the typeid operator.
Program Code
1. #include <iostream>
2. using namespace std;
3. // Initialization of base class
4. class B
5. {
6. virtual void fun() {}
7. };
8. // Initialization of Derived class
9. class D : public B
10. { };
11. // Driver Code
12. int main()
13. {
14. //create pointer of Base class
15. B* b = new D;
16. //create Derived class pointer
17. D* d = dynamic_cast<D*>(b);
18. if (d != NULL)
19. cout << "Working ......";
20. else
21. cout << "c\Cannot cast B* to D*";
22. getchar();
23. return 0;
24. }
Output
Working
Explanation
Here , we have created a virtual function in Class B and derived class D from this class. If we don't create a virtual function in class B, it will generate an error
8. Memory leak
Memory leaking happens in C++ when programmers allocate memory with the new keyword but fail to deallocate it with the delete() operator or function.
The most common memory leak in C++ is caused by employing the incorrect delete operator.
To remove a single allocated memory space it uses the delete operator, or to free an array of data values it ssss the delete [] operator.
Program Code
1. #include <iostream>
2. #include <cstdlib>
3. using namespace std;
4. int main()
5. {
6. int* ptr;
7. ptr = (int*) malloc(sizeof(int));
8. if (ptr == NULL)
9. cout << "Memory Is Insuffficient\n";
10. else
11. {
12. free(ptr);
13. cout << "Memory Freed\n";
14. }
15. }
Output
Memory Freed
Explanation
In this programme , we check if allcoated memory is freed or not .
9. kbhit
The kbhit() function represents a keyboard hit. It deals with keyboard pressing.
The conio.h header file contains the kbhit() function. This function's primary use is to determine whether a key has been depressed or not. It returns a value between 0 and 1 based on whether the key is depressed or not.
Program Code
1. #include <iostream.h>
2. #include <conio.h>
3. int main()
4. {
5. while (!kbhit())
6. printf("Press a key\n");
7. return 0;
8. }
Output
"Press a key"
Explanation
This prints "Press a key" until user presses a key on the keyboard as we have used kbhit().
10 .Type Erasure
Type Erasure is used To create generic container that can handle a variety of concrete types.This technique is also known as duck-typing.
In C++, type erasure is performed by wrapping a concrete implementation in a generic wrapper and providing the concrete implementation with virtual accessor functions via a generic interface.
Type Erasure enables the use of many concrete types via a single generic interface. Object orientation is the usual C++ way of type erasure; a void pointer is used in C. This approach is unsafe because each type requires its own compare function.
Program Code
1. #include <iostream>
2. class getRandomN
3. {
4. size_t count;
5. public:
6. getRandomN(int n = 1) : count(n) {}
7. template <class Container>
8. operator Container ()
9. {
10. Container c;
11. for(size_t i = 0;i < count; ++i)
12. c.insert(c.end(), rand());
13. return c;
14. }
15. };
16. int main()
17. {
18. std::set<int> random_s = getRandomN(10);
19. std::vector<int> random_v = getRandomN(10);
20. std::list<int> random_l = getRandomN(10);
21. }
Output
4,7,5,2,1,3,9,6,8,0
Explanation
In C++, type erasure is performed by wrapping a concrete implementation in a generic wrapper and providing the concrete implementation with virtual accessor functions via a generic interface.It print ten random number.
11. Virtual Constructor
Virtual Constructor is used to making a copy or new item without knowing its exact type.It can be implemented by utilizing overloaded methods with the polymorphic assignment.It is also known as the Factory method and design pattern.
It polymorphic generation and copying of objects by outsourcing the act of creation and copying to the derived class with the help of virtual methods.
Program Code
1. #include<iostream>
2. using namespace std;
3. class b
4. {
5. public:
6. b()
7. {
8. //constructor of b
9. cout<<"Constructing base \n";
10. }
11. // destructor of b
12. virtual ~b()
13. {
14. cout<<"Destructing base \n";
15. }
16. };
17. //derive class from A
18. class d: public b
19. {
20. public:
21. d()
22. {
23. cout<<"Constructing is derived \n";
24. }
25. ~d()
26. {
27. cout<<"Destructing is derived \n";
28. }
29. };
30. int main(void)
31. {
32. d *derived = new d();
33. b *bptr = derived;
34. delete bptr;
35. return 0;
36. }
Output
Constructing base
Constructing derived
Destructing derived
Destructing base
Explanation
In this example, we have derived the class from the base class and called their constructor and Destructor.
12. Stack unwinding
stack unwinding is the process of removing function entries during runtime from the function call stack. It is releted to exception handling.
It occurs when a thrown exception is not caught in a particular scope
Unwinding a Function terminates that function
- All local variables of the function are destroyed or Invoke destructors
- Control returns to the point where the function was called .
In outer try...catch blocks, attempts are made to catch the exception.If a destructor throws an exception during stack unwinding and that exception is not handled, the terminate() method get called.
Program Code
#include <iostream>
using namespace std;
void a() throw(int)
{
cout << "\n function 1 Start ";
throw 100;
cout << "\n function 1 End ";
}
void b() throw(int)
{
cout << "\n function 2 Start ";
a();
cout << "\n function 3 End ";
}
void c()
{
cout << "\n function 3 Start ";
try
{
b();
}
catch (int i)
{
cout << "\n Caught Exception: " << i;
}
cout << "\n function 3 End";
}
int main()
{
c();
getchar();
return 0;
}
Output
function 3 Start
function 2 Start
function 1 Start
Caught Exception: 100
function 3 End
Explanation
Here, control first enters function 2, then function 3, and last function 1.
After that, if one exception happens, all of the data is removed from the stack, and function 3 is once more reached.
13. Vtable
Most C++ implementations handle polymorphism using V-tables or virtual tables.Most C++ implementations handle polymorphism using V-tables (or virtual tables).
The compiler creates a virtual table for each class that contains virtual functions.In contain an entry for each virtual function that the class can access and stores a pointer to its definition.The vtable only stores the most specific function definition that the class can call.
There is a table of function pointers to all virtual methods for each concrete implementation of a class.All objects contain a pointer to this table.
Program Code
1. #include <iostream>
2. using namespace std;
3. class A
4. {
5. int num1=10;
6. public:
7. void display()
8. {
9. std::cout << "Value of num1 is : " << num1<<std::endl;
10. }
11. };
12. //derive class B from S
13. class B: public A
14. {
15. };
16. int main()
17. {
18. //create obj of class A
19. A *a;
20. B b;
21. a = &b;
22. a->display();
23. return 0;
24. }
Output
Value of x is : 10
Explanation
The base class pointer in this case is * a.It can only access the members of the base class; it cannot access the members of the derived class. However, with the use of a virtual function, it is able to access the derived class members.
14. constexpr
constexpr specifies that the value of a variable or function can appear in constant expressions.
It specifiy that the value of an object or a function can be evaluated at compile-time and this expression can be used in other constant expressions.
In C++ 11, a constexpr function should contain only one return statement whereas C++ 14 allows more than one statement. It state that only constant global variables should be used with the constexpr function.It is able to only other constexpr function not simple function.
Program Code
1. #include <iostream>
2. constexpr int sum(int a, int b) { return (a + b); }
3. int main()
4. {
5. //perform sum of a b
6. constexpr int a = sum(10, 20);
7. std::cout << "sum = "<<a;
8. return 0;
9. }
Output
sum = 30
Explanation
Here we have used constexpr to indicate compiler to perform operation value at compile time .
15.Containers and algorithm
The Containers library is a general set of class templates and algorithms that let programmers quickly implement widely-used data structures like queues, lists, and stacks.
There are three classes of containers:
- sequence containers
- associative container
- unordered associative containers
Each of which is designed to support a different set of operations.
Program Code
1. #include <iostream>
2. #include <vector>
3. using namespace std;
4. int main()
5. {
6. vector<int> numbers = {25,78,35,90,12,34,45};
7. cout << "Numbers Present in vector: ";
8. for(auto &num: numbers)
9. {
10. cout << num << " ";
11. }
12. return 0;
13. }
Output
Numbers Present in vector: 25 78 35 90 12 34 45
Explanation
Here, we have used the vector class to demonstrate the working of a sequential container ,which is a type of container . It stores the int value and prints its value.
16. Raw String
Raw String is a Literal constant whose value remain same until the life of program.
It ingore escape characters like ' \n, \t," and many more .It is denoted by R .
The syntax for Raw string :
R "delimiter( raw_characters )delimiter"
R"(OpenGenus.\nWelcome to OpneGenus.\n)";
Program Code
#include <iostream>
using namespace std;
int main()
{
string str1 = ".\nThis is line 1.\nThis is line 2.\n";
string str2 = R"(This is line 1.\nThis is line 2.\n)";
cout <<"Normal String = "<< str1 << endl;
cout <<"Raw String = "<<str2 << endl;
return 0;
}
Output
Normal String = .
This is line 1.
This is line 2.
Raw String = This is line 1.\nThis is line 2.\n
Explanation
Here,We have printed Noraml string and Raw String with the help of Raw String Literal.
17. Dynamic memory allocation
The new operator is used to allocate new memory.It sets the memory to the pointer variable and returns its address if enough memory is available.
synatx : pointer_variable = new datatype(value);
The delete operator is used to deallocate the memory. It is employed to deallocate the memory that a new operator created.
syntax :delete[ ] pointer_variable;
Program Code
1. #include <iostream>
2. using namespace std;
3. int main()
4. {
5. // declare an int pointer
6. int* pointInt;
7. // dynamically allocate memory
8. pointInt = new int;
9. *pointInt = 50;
10. //print values
11. cout << "Integer Value before deallocation = "<< *pointInt << endl;
12. //deallocation of memory
13. delete pointInt;
14. // print value
15. cout << "Integer Value after deallocation = "<< *pointInt << endl;
16. return 0;
17. }
Output
Integer Value before deallocation = 50
Integer Value after deallocation = 0
Explanation
In this programme, the memory was allotted to the pointer with the new keyword and the memory was released with the delete keyword. and value before and after deallocation and displyed value after and before deallocation.
18. decltype
decltype(auto) was added in C++ 14 .This allows auto declarations to use the decltype rules on the given expression. It is used with return type deduction, by using decltype(auto) syntax instead of auto for the function's return type deduction.
Program Code
1. #include <bits/stdc++.h>
2. using namespace std;
3. int main()
4. {
5. auto a = 4;
6. auto b='a';
7. auto c = 3.37;
8. auto d = &a;
9. cout <<"Value of a = "<<a<< " Type of a = "<<typeid(a).name()<<endl;
10. cout <<"Value of b = "<<b<< " Type of a = "<<typeid(b).name()<<endl;
11. cout <<"Value of c = "<<c<< " Type of a = "<<typeid(c).name()<<endl;
12. cout <<"Value of d = "<<d<< " Type of a = "<<typeid(d).name()<<endl;
13. return 0;
14. }
Output
Value of a = 4 Type of a = i
Value of b = a Type of a = c
Value of c = 3.37 Type of a = d
Value of d = 0x7fff5a407474 Type of a = Pi
Explanation
Here , we have printed value of variable and its type with the help decltype.
19. CHAR_BIT
CHAR_BIT represent the number of bits present in char. This function is present in “limits.h” header file of C++ language. It is of 8-bits per byte.
Program Code
// CPP program to print byte by byte presentation
#include <bits/stdc++.h>
using namespace std;
void BinaryNumber(int value)
{
int n = CHAR_BIT*sizeof(value);
stack<bool> s;
for (int i=1; i<=n; i++)
{
s.push(value%2);
value = value/2;
}
for (int i=1; i<=n; i++)
{
cout << s.top();
s.pop();
if (i % CHAR_BIT == 0)
cout << " ";
}
}
int main()
{
int value = 5;
std::cout<<"value = 5 "<<endl;
std::cout<<"Binary Number is = ";
BinaryNumber(value);
return 0;
}
Output
value = 5
Binary Number is = 00000000 00000000 00000000 00000101
Explanation
It display value of number in binary format with the help of CHAR_BIT.
20. Uniform initialization
Uniform initialization is a feature in C++ which was added in C++ 11.It introduces brace-initialization that uses braces ({}) to enclose initializer values. The syntax is as follows:
type var_name{arg1, arg2, ....arg n}
Program Code
#include <bits/stdc++.h>
using namespace std;
int main()
{
// declaring a dynamic array initializing using braces
int* num = new int[10]{ 11,23,15,37,28,29,89,7,56,45};
cout << "Number in array = "<<endl;
for (int i = 1; i <10; i++)
cout << *(num + i) << " ";
}
Output
Number in array
23 15 37 28 29 89 7 56 45
Explanation
As we know that ,Uniform initialization use brace-initialization brace ({}) to initializ value. and display result.
LETS CHECK YOUR KNOWELDGE :
Question
what is maximum number of child node binary tree can have ?
Question 2
which of the follwing is not type of casting operators?
Sign up for FREE 3 months of Amazon Music. YOU MUST NOT MISS.