Important Topics On C++ by Deepak Mitra
Important Topics On C++ by Deepak Mitra
Empty Classes
#include<iostream>
using namespace std;
int main()
{
cout << sizeof(Empty);
return 0;
}
Output:
Size of an empty class is not zero. It is 1 byte generally. It is nonzero to ensure that the two different
objects will have different addresses. To an object of an empty class, 1 byte is allocated by compiler for
unique address identification. So, if a class have multiple objects they can have different unique memory
location. Suppose, if a class does not have any size, what would be stored on the memory location?
That’s the reason when we create an object of an empty class in C++ program, it needs some memory to
get stored, and the minimum amount of memory that can be reserved is 1 byte.
So, if we create multiple objects of an empty class, every object will have unique address.
#include<iostream>
using namespace std;
class Empty { };
int main()
{
Empty a, b;
if (&a == &b)
cout << "Both object have same address"<< endl;
else
cout << "Both object have unique address" << endl;
1
Important Topics in C++
return 0;
}
Output:
Fine
For the same reason (different objects should have different addresses), “new” always returns pointers
to distinct objects. See the following example.
#include<iostream>
using namespace std;
class Empty { };
int main()
{
Empty* p1 = new Empty;
Empty* p2 = new Empty;
if (p1 == p2)
cout << "impossible " << endl;
else
cout << "Fine " << endl;
return 0;
}
Output:
Fine
#include<iostream>
using namespace std;
class Empty { };
int main()
{
cout << sizeof(Derived);
return 0;
}
2
Important Topics in C++
Note that the output is not greater than 4. There is an interesting rule that says that an empty base class
need not be represented by a separate byte. So compilers are free to make optimization in case of
empty base classes. As an excercise, try the following program on your compiler.
#include <iostream>
using namespace std;
class Empty
{};
class Dummy
{
char c;
};
int main()
{
cout << "sizeof(Empty) " << sizeof(Empty) << endl;
cout << "sizeof(Derived1) " << sizeof(Derived1) << endl;
cout << "sizeof(Derived2) " << sizeof(Derived2) << endl;
cout << "sizeof(Derived3) " << sizeof(Derived3) << endl;
cout << "sizeof(Derived4) " << sizeof(Derived4) << endl;
cout << "sizeof(Dummy) " << sizeof(Dummy) << endl;
return 0;
}
3
Important Topics in C++
If an empty class contain virtual function, even though there is no data members in the class, its size will
not be 1 byte but 4 byte because of virtual pointer i.e. VPTR. Virtual pointer size on 32 bit platform is 4
bytes and on 64 bit it is 8 bytes.
When we make a function as a virtual, compiler automatically set a hidden VPTR as a class data member
field. So, no longer a class is an empty class that contains virtual function in C++.
For example size of below class that contain virtual function will be 4 bytes.
class ClassWithVirtualFunctions{
public:
virtual void display(){
}
};
int main(){
return 0;
}
Size of void pointer on 16 bit Platform is : 2 bytes , on 32 bit : 4 bytes and on 64 bit : 8 bytes. Size of
void* is of same size in C/C++, but, the size of void pointer is platform dependent.
On 32 bit platform Size of void* is 4 byte. In fact, any kind of pointer we consider i.e. int , char or float
etc. all have same size and size could be 4 bytes or 8 bytes depend upon platform we are using i.e.32 bit
or 64 bit etc.
Actually, whatever are pointer types, that store only address of the variables they point to, whatever it
is int, float or char etc. so, size for all pointers would be same.
If we consider 32 bit platform, size of all pointers will be of 4 bytes size. And if it is 64 bit, it would be of
8 byte.
NOTE:
4
Important Topics in C++
To find a size of void pointer variables, we can use sizeof operator in c or c++ program. On window 64
bit machine, generally, we should find 32 bit and 64 bit support. So, if we want to check the size of void
pointer in 64 bit or 32 bit platform then we need to check the project properties for platform x86(32 bit)
or x64(64 bit) in visual studio IDE. Then we can see the size of void* as 4 or 8 byte depending upon
configuration for 32 bit or 64 bit respectively.
int main(){
void *a;
return 0;
}
Below are default functions provided by compiler in C++ language if not implemented in a class by a
software developer.
Default constructor
Copy constructor
Assignment operator
Destructor
Constructors in C++
What is constructor?
A constructor is a member function of a class which initializes objects of a class. In C++, Constructor is
automatically called when object(instance of class) create. It is special member function of the class.
If we do not specify a constructor, C++ compiler generates a default constructor for us (expects no
parameters and has an empty body).
5
Important Topics in C++
Types of Constructors
Default Constructors:
Default constructor is the constructor which doesn’t take any argument. It has no parameters.
class construct {
public:
int a, b;
// Default Constructor
construct()
{
a = 10;
b = 20;
}
};
int main()
{
// Default constructor called automatically
// when the object is created
construct c;
cout << "a: " << c.a << endl
<< "b: " << c.b;
return 1;
}
Output:
a: 10
b: 20
Note: Even if we do not define any constructor explicitly, the compiler will automatically provide a
default constructor implicitly.
6
Important Topics in C++
Parameterized Constructors
It is possible to pass arguments to constructors. Typically, these arguments help initialize an object when
it is created. To create a parameterized constructor, simply add parameters to it the way you would to
any other function. When you define the constructor’s body, use the parameters to initialize the object.
class Point {
private:
int x, y;
public:
// Parameterized Constructor
Point(int x1, int y1)
{
x = x1;
y = y1;
}
int getX()
{
return x;
}
int getY()
{
return y;
}
};
int main()
{
// Constructor called
Point p1(10, 15);
return 0;
}
Output:
7
Important Topics in C++
When an object is declared in a parameterized constructor, the initial values have to be passed as
arguments to the constructor function. The normal way of object declaration may not work. The
constructors can be called explicitly or implicitly.
It is used to initialize the various data elements of different objects with different values when they are
created.
Copy Constructor
A copy constructor is a member function which initializes an object using another object of the same
class.
Whenever we define one or more non-default constructors( with parameters ) for a class, a default
constructor( without parameters ) should also be explicitly defined as the compiler will not provide a
default constructor in this case. However, it is not necessary but it’s considered to be the best practice
to always define a default constructor.
// Illustration
#include "iostream"
using namespace std;
class point {
private:
double x, y;
public:
// Non-default Constructor & default Constructor
point (double px, double py) {
x = px, y = py;
}
};
int main(void) {
8
Important Topics in C++
A copy constructor is a member function which initializes an object using another object of the same
class. A copy constructor has the following general function prototype:
#include<iostream>
using namespace std;
class Point
{
private:
int x, y;
public:
Point(int x1, int y1) { x = x1; y = y1; }
// Copy constructor
Point(const Point &p2) {x = p2.x; y = p2.y; }
int main()
{
Point p1(10, 15); // Normal constructor is called here
Point p2 = p1; // Copy constructor is called here
9
Important Topics in C++
return 0;
}
Output:
It is, however, not guaranteed that a copy constructor will be called in all these cases, because the C++
Standard allows the compiler to optimize the copy away in certain cases,
If we don’t define our own copy constructor, the C++ compiler creates a default copy constructor for
each class which does a member-wise copy between objects. The compiler created copy constructor
works fine in general. We need to define our own copy constructor only if an object has pointers or any
runtime allocation of the resource like file handle, a network connection..etc.
Deep copy is possible only with user defined copy constructor. In user defined copy constructor,
we make sure that pointers (or references) of copied object point to new memory locations.
10
Important Topics in C++
Which of the following two statements call copy constructor and which one calls assignment
operator?
Copy constructor is called when a new object is created from an existing object, as a copy of the existing
object. Assignment operator is called when an already initialized object is assigned a new value from
another existing object. In the above example (1) calls copy constructor and (2) calls assignment
operator.
#include<iostream>
#include<cstring>
using namespace std;
class String
{
private:
char *s;
int size;
11
Important Topics in C++
public:
String(const char *str = NULL); // constructor
~String() { delete [] s; }// destructor
String(const String&); // copy constructor
void print() { cout << s << endl; } // Function to print string
void change(const char *); // Function to change
};
int main()
{
String str1("CDAC CoE ");
String str2 = str1;
12
Important Topics in C++
What would be the problem if we remove copy constructor from above code?
If we remove copy constructor from the above program, we don’t get the expected output. The changes
made to str2 reflect in str1 as well which is never expected.
#include<iostream>
#include<cstring>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL); // constructor
~String() { delete [] s; }// destructor
void print() { cout << s << endl; }
void change(const char *); // Function to change
};
int main()
{
String str1("CDAC CoE ");
String str2 = str1;
13
Important Topics in C++
return 0;
}
Can we make copy constructor private?
Yes, a copy constructor can be made private. When we make a copy constructor private in a class,
objects of that class become non-copyable. This is particularly useful when our class has pointers or
dynamically allocated resources. In such situations, we can either write our own copy constructor like
above String example or make a private copy constructor so that users get compiler errors rather than
surprises at runtime.
Why argument to a copy constructor must be passed as a reference?
A copy constructor is called when an object is passed by value. Copy constructor itself is a function. So if
we pass an argument by value in a copy constructor, a call to copy constructor would be made to call
copy constructor which becomes a non-terminating chain of calls. Therefore compiler doesn’t allow
parameters to be passed by value.
When we create our own copy constructor, we pass an object by reference and we generally pass it as a
const reference.
One reason for passing const reference is, we should use const in C++ wherever possible so that objects
are not accidentally modified. This is one good reason for passing reference as const, but there is more
to it. For example, predict the output of following C++ program. Assume that copy elision is not done by
compiler.
Note : In the context of the C++ programming language, return value optimization (RVO) is a compiler
optimization that involves eliminating the temporary object created to hold a function's return
value. RVO is particularly notable for being allowed to change the observable behaviour of the
resulting program by the C++ standard
#include<iostream>
using namespace std;
class Test
{
/* Class data members */
public:
Test(Test &t) { /* Copy data members from t*/}
14
Important Topics in C++
Test fun()
{
cout << "fun() Called\n";
Test t;
return t;
}
int main()
{
Test t1;
Test t2 = fun();
return 0;
}
Output:
The program looks fine at first look, but it has compiler error. If we add const in copy constructor, the
program works fine, i.e., we change copy constructor to following.
Or if we change the line “Test t2 = fun();” to following two lines, then also the program works fine.
Test t2;
t2 = fun();
The function fun() returns by value. So the compiler creates a temporary object which is copied to t2
using copy constructor in the original program (The temporary object is passed as an argument to copy
constructor). The reason for compiler error is, compiler created temporary objects cannot be bound to
non-const references and the original program tries to do that. It doesn’t make sense to modify
compiler created temporary objects as they can die any moment.
A copy constructor is called whenever a new variable is created from an object. This happens in the
following cases (but not in assignment).
15
Important Topics in C++
C++ calls a copy constructor to make a copy of an object in each of the above cases. If there is no copy
constructor defined for the class, C++ uses the default copy constructor which copies each field, ie,
makes a shallow copy.
If the object has no pointers to dynamically allocated memory, a shallow copy is probably sufficient.
Therefore the default copy constructor, default assignment operator, and default destructor are ok and
you don't need to write your own.
If you need a copy constructor, you also need a destructor and operator=
If you need a copy constructor, it's because you need something like a deep copy, or some other
management of resources. Thus is is almost certain that you will need a destructor and override the
assignment operator.
The copy constructor takes a reference to a const parameter. It is const to guarantee that the copy
constructor doesn't change it, and it is a reference because a value parameter would require making a
copy, which would invoke the copy constructor, which would make a copy of its parameter, which would
invoke the copy constructor, which ...
Here is an example of a copy constructor for the Point class, which doesn't really need one because the
default copy constructor's action of copying fields would work fine, but it shows how it works.
16
Important Topics in C++
class Point {
public:
...
Point(const Point& p); // copy constructor
...
//=== file Point.cpp ==========================================
...
Point::Point(const Point& p) {
x = p.x;
y = p.y;
}
...
//=== file my_program.cpp ====================================
...
Point p; // calls default constructor
Point s = p; // calls copy constructor.
p = s; // assignment, not copy constructor.
A copy constructor is used to initialize a newly declared variable from an existing variable. This makes a
deep copy like assignment, but it is somewhat simpler:
C++ compiler provide default copy constructor (and assignment operator) with class. When we don’t
provide implementation of copy constructor (and assignment operator) and tries to initialize object with
already initialized object of same class then copy constructor gets called and copies members of class
one by one in target object.
The problem with default copy constructor (and assignment operator) is – When we have members
which dynamically gets initialized at run time, default copy constructor copies this members with
address of dynamically allocated memory and not real copy of this memory. Now both the objects
points to the same memory and changes in one reflects in another object, Further the main disastrous
effect is, when we delete one of this object other object still points to same memory, which will be
dangling pointer, and memory leak is also possible problem with this approach.
17
Important Topics in C++
Hense, in such cases, we should always write our own copy constructor (and assignment operator).
#include<iostream>
#include<stdio.h>
class Test
{
public:
Test() {}
Test(const Test &t)
{
cout<<"Copy constructor called "<<endl;
}
// Driver code
int main()
{
Test t1, t2;
t2 = t1;
Test t3 = t1;
getchar();
return 0;
}
Output:
Copy constructor is called when a new object is created from an existing object, as a copy of the existing
object (see this G-Fact). And assignment operator is called when an already initialized object is assigned
a new value from another existing object.
18
Important Topics in C++
Sometimes it is useful for a constructor to be able to call another constructor of the same class. This
feature, called Constructor Delegation, was introduced in C++ 11.
class A {
int x, y, z;
public:
A()
{
x = 0;
y = 0;
z = 0;
}
A(int z)
{
// The below two lines are redundant
x = 0;
y = 0;
void show()
{
cout << x << '\n'
<< y << '\n'
<< z;
}
};
int main()
{
A obj(3);
obj.show();
19
Important Topics in C++
return 0;
}
class A {
int x, y, z;
public:
A()
{
init();
z = 0;
}
A(int z)
{
init();
this->z = z;
}
void show()
{
cout << x << '\n'
<< y << '\n'
<< z;
}
};
20
Important Topics in C++
int main()
{
A obj(3);
obj.show();
return 0;
}
Solving above redundant code problem using constructor delegation()
While the usage of an init() function eliminates duplicate code, it still has its own drawbacks. First, it’s
not quite as readable, as it adds a new function and several new function calls. Second, because init() is
not a constructor, it can be called during the normal program flow, where member variables may
already be set and dynamically allocated memory may already be allocated. This means init() needs to
be additionally complex in order to handle both the new initialization and re-initialization cases
properly.
However, C++ Constructor delegation provides an elegant solution to handle this problem, by allowing
us to call a constructor by placing it in the initializer list of other constructors. The following program
demonstrates how it is done:
public:
A()
{
x = 0;
y = 0;
z = 0;
}
// Constructor delegation
A(int z) : A()
{
this->z = z; // Only update z
}
void show()
{
cout << x << '\n'
<< y << '\n'
21
Important Topics in C++
<< z;
}
};
int main()
{
A obj(3);
obj.show();
return 0;
}
It is very important to note that constructor delegation is different from calling a constructor from inside
the body of another constructor, which is not recommended because doing so creates another object
and initializes it, without doing anything to the object created by the constructor that called it.
A constructor is a special member function of a class which initializes objects of a class. In C++,
constructor is automatically called when object of a class is created.
By default, constructors are defined in public section of class. So, question is can a constructor be
defined in private section of class ?
Answer : Yes, Constructor can be defined in private section of class
Using Friend Class : If we want that class should not be instantiated by anyone else but only by a
friend class.
// class A
class A{
private:
A(){
cout << "constructor of A\n";
}
friend class B;
};
22
Important Topics in C++
B(){
A a1;
cout << "constructor of B\n";
}
};
// Driver program
int main(){
B b1;
return 0;
}
Output:
constructor of A
constructor of B
If you comment the line friend class B, you will encounter below error:
A(){
A a1;
Using Singleton design pattern: When we want to design a singleton class. This means instead of
creating several objects of class, the system is driven by a single object or a very limited number of
objects.
Named Constructor Idiom : Since constructor has same name as of class, different constructors are
differentiated by their parameter list, but if numbers of constructors is more, then implementation
can become error prone.
With the Named Constructor Idiom, you declare all the class’s constructors in the private or protected
sections, and then for accessing objects of class, you create public static functions.
23
Important Topics in C++
// Rectangular coordinates
Point(float x, float y);
// rectangular(x, y)
static Point Rectangular(float, float);
void display();
24
Important Topics in C++
};
// rectangular coordinates
Point pr = Point::Rectangular(5.7,1.2);
cout << "rectangular coordinates \n";
pr.display();
return 0;
}
Output :
polar coordinates
x :: 2.06544
y :: 5.31262
rectangular coordinates
x :: 5.7
y :: 1.2
In C++, if a class has a constructor which can be called with a single argument, then this constructor
becomes conversion constructor because such a constructor allows automatic conversion to the class
being constructed.
25
Important Topics in C++
#include <iostream>
class MyClass {
int a, b;
public:
MyClass(int i)
{
a = i;
b = i;
}
void display()
{
std::cout << " a = " << a << " b = " << b << "\n";
}
};
int main()
{
MyClass object(10);
object.display();
a = 10 b = 10
a = 20 b = 20
Conversion Constructors: There are constructors that convert types of its parameter into a type of the
class. The compiler uses these constructors to perform implicit class-type conversions. These
conversions are made by invoking the corresponding constructor with matches the list of values/objects
that are assigned to the object.
This previous example only deals with one parameter, to extend it to several parameters i.e., extended
initializer lists or braced-init-lists. That is, we enclose the parameters to be passed to it inside a pair of
curly braces ({}).
#include <iostream>
26
Important Topics in C++
class MyClass {
int a, b;
public:
MyClass(int i, int y)
{
a = i;
b = y;
}
void display()
{
std::cout << " a = " << a << " b = " << b << "\n";
}
};
int main()
{
MyClass object(10, 20);
object.display();
Output:
a = 10 b = 20
a = 30 b = 40
Note:
27
Important Topics in C++
When the return type of a function is a class, instead of returning a object, we can return a braced-init-
list, now since the return type is a class instance, a object of that class is created with the braced-init-list,
given that the class has a corresponding conversion constructor.
Example:
This function create_object will return a MyClass object with a and b values as the x and y passed to the
function.
As a parameter to a function:
When a function’s parameter type is of a class, instead of passing a object to the function, we can pass
a braced-init-list to the function as the actual parameter, given that the class has a corresponding
conversion constructor.
An example :
// This function is invoked in the main function with a braced-init-list with two integers as the
parameter.
// e.g. :
// display_object({10, 20});
Note: This function display_object creates a new class instance of MyClass called obj and will call its
member function display().
-------------------------------------------------------------------------------------------------------------------------------------
The two parts in which our memory is divided. These parts are as follows:
28
Important Topics in C++
stack - Memory from the stack is used by all the members which are declared inside functions. Note
that main is also a function.
heap - This memory is unused and can be used to dynamically allocate the memory at runtime.
new
The new operator is used to allocate memory at runtime. The memory is allocated in bytes.
By writing new int, we allocated the space in memory required by an integer. Then we assigned the
address of that memory to an integer pointer ptr.
*ptr = 4;
Thus, we allocated that much space in memory that would be required by an int and then assigned
the address of that memory to a pointer ptr and assigned the memory a value 4.
We can initialize a variable while dynamical allocation in the following two ways.
#include <iostream>
int main()
{
int *ptr = new int;
*ptr = 4;
std::cout << *ptr << std::endl;
return 0;
}
The main use of the concept of dynamic memory allocation is for allocating arrays when we have to
declare an array by specifying its size but are not sure about the size.
Consider a situation when we want the user to enter the name but are not sure about the number of
characters in the name that the user will enter. In that case, we will declare an array of characters for
29
Important Topics in C++
the name with some array size such that the array size should be sufficient enough to hold any name
entered. Suppose we declared the array with the array size 30 as follows.
char name[30];
And if the user enters the name having only 12 characters, then the rest of the memory space which was
allocated to the array at the time of its declaration would become waste, thus unnecessary consuming
the memory.
In this case, we will be using the new operator to dynamically allocate the memory at runtime. We use
the new operator as follows.
#include <iostream>
int main()
{
int length, sum = 0;
cout << "Enter the number of students in the group" << endl;
cin >> length;
int *marks = new int[length];
cout << "Enter the marks of the students" << endl;
for( int i = 0; i < length; i++ ) // entering marks of students
{
cin >> *(marks+i);
}
for( int i = 0; i < length; i++ ) // calculating sum
{
sum += *(marks+i);
}
cout << "sum is " << sum << endl;
return 0;
}
In this example, we are calculating the sum of the marks of all the students of a group. Since different
groups have a different number of students, therefore we are asking the number of students ( i.e.the
size of the array ) every time we are running the program. In this example, the user entered the size as
4.
int *marks = new int[length];
30
Important Topics in C++
We declared an array of integer and allocated it some space in memory dynamically equal to the size
which would be occupied by length number of integers. Thus it is allocated a space equal to 'length *
(size of 1 integer)' and assigned the address of the assigned memory to the pointer marks. The rest of
the steps must be clear to you.
We call this array dynamic because it is being assigned memory when the program runs. We made this
possible by using the new operator. This dynamic array is being allocated memory from heap unlike
other fixed arrays which are provided memory from stack. We can give any size to these dynamic arrays
and there is no limitation to it.
delete
Suppose we allocated some memory to a variable dynamically and then we realize that the variable is
not needed anymore in the program. In that case, we need to free the memory which we had assigned
to that variable. For that, we use the delete operator.
It is advised to free the dynamically allocated memory after the program finishes so that it becomes
available for future use.
To delete the memory assigned to a variable, we simply need to write the following code.
delete ptr;
There is nothing much to understand in this. The delete operator simply returns the memory allocated
back to the operating system so that it can be used again. Let's look at an example.
#include <iostream>
int main()
{
int *ptr = new int;
*ptr = 4;
std::cout << *ptr << std::endl;
delete ptr;
return 0;
}
31
Important Topics in C++
After printing the value 4, we deleted the pointer i.e. deleted the address of the allocated memory thus
freeing it.
Once deleted, a pointer will point to deallocated memory and will be called a dangling pointer. If we
further try to delete a dangling pointer, we will get some undefined behavior.
Deleting Array
To delete an array which has been allocated in this way, we write the following code.
delete[] ptr;
#include <iostream>
int main()
{
int length, sum = 0;
cout << "Enter the number of students in the group" << endl;
cin >> length;
int *marks = new int[length];
cout << "Enter the marks of the students" << endl;
for( int i = 0; i < length; i++ ) // entering marks of students
{
cin >> *(marks+i);
}
for( int i = 0; i < length; i++ ) // calculating sum
{
sum += *(marks+i);
}
cout << "sum is " << sum << endl;
delete[] marks;
return 0;
}
We just wrote delete[ ] marks; at the end of the program to release the memory which was dynamically
allocated using new.
32
Important Topics in C++
As we know that Constructor is a member function of a class which is called whenever a new object is
created of that class. It is used to initialize that object. Destructor is also a class member function which
is called whenever the object goes out of scope.
Destructor is used to release the memory assigned to the object. It is called in these conditions.
For a global object, operator is applied to a pointer to the object of the class
#include <iostream>
class A
{
public:
A() {
cout << "Constructor" << endl;
}
~A() {
cout << "Destructor" << endl;
}
};
int main()
{
A* a = new A[4];
delete [] a; // Delete array
return 0;
}
Output
The Constructor will be called four times since we are allocating memory to four objects of the class 'A'.
The Destructor will also be called four times during each of these objects.
How to make a C++ class whose objects can only be dynamically allocated?
The problem is to create a class such that the non-dynamic allocation of object causes compiler error.
For example, create a class ‘Test’ with following rules.
33
Important Topics in C++
The idea is to create a private destructor in the class. When we make a private destructor, the compiler
would generate a compiler error for non-dynamically allocated objects because compiler need to
remove them from stack segment once they are not in use.
Since compiler is not responsible for deallocation of dynamically allocated objects (programmer should
explicitly deallocate them), compiler won’t have any problem with them. To avoid memory leak, we
create a friend function destructTest() which can be called by users of class to destroy objects.
#include <iostream>
using namespace std;
int main()
{
/* Uncommenting following following line would cause compiler error */
// Test t1;
// create an object
Test *ptr = new Test;
return 0;
}
Object Created
34
Important Topics in C++
Destroying Object
Object Destroyed
If we don’t want to create a friend function, we can also overload delete and delete[] operators in Test,
this way we don’t have to call a specific function to delete dynamically allocated objects.
C++ programming language allows both auto(or stack allocated) and dynamically allocated objects. In
java & C#, all objects must be dynamically allocated using new.
C++ supports stack allocated objects for the reason of runtime efficiency. Stack based objects are
implicitly managed by C++ compiler. They are destroyed when they go out of scope and dynamically
allocated objects must be manually released, using delete operator otherwise memory leak occurs. C++
doesn’t support automatic garbage collection approach used by languages such as Java & C#.
Test t; // OK
The idea of is to keep new operator function private so that new cannot be called. See the following
program. Objects of ‘Test’ class cannot be created using new as new operator function is private in
‘Test’. If we uncomment the 2nd line of main(), the program would produce compile time error.
#include <iostream>
using namespace std;
int main()
{
// Uncommenting following line would cause a compile time error.
35
Important Topics in C++
Constructor is called
x=9
Destructor is executed
The new and delete operators can also be overloaded like other operators in C++. New and Delete
operators can be overloaded globally or they can be overloaded for specific classes.
If these operators are overloaded using member function for a class, it means that these operators are
overloaded only for that specific class.
If overloading is done outside a class (i.e. it is not a member function of a class), the overloaded ‘new’
and ‘delete’ will be called anytime you make use of these operators (within classes or outside classes).
This is global overloading.
The overloaded new operator receives size of type size_t, which specifies the number of bytes of
memory to be allocated. The return type of the overloaded new must be void*.The overloaded function
returns a pointer to the beginning of the block of memory allocated.
The function receives a parameter of type void* which has to be deleted. Function should not return
anything.
NOTE: Both overloaded new and delete operator functions are static members by default. Therefore,
they don’t have access to this pointer .
36
Important Topics in C++
return p;
}
int main()
{
student * p = new student("Yash", 24);
p->display();
delete p;
}
Overloading new operator with size: 16
37
Important Topics in C++
Constructor is called
Name:Yash
Age:24
NOTE: In the above new overloaded function, we have allocated dynamic memory through new
operator, but it should be global new operator otherwise it will go in recursion
void *p = new student(); // this will go in recursion asnew will be overloaded again and again
void *p = ::new student(); // this is correct
int main()
{
int n = 5, i;
int * p = new int[3];
38
Important Topics in C++
delete p;
}
Output :
Array: 0 1 2 3 4
NOTE: In the code above, in new overloaded function we cannot allocate memory using ::new int[5] as it
will go in recursion. We need to allocate memory using malloc only.
The overloaded new operator function can accept arguments; therefore, a class can have multiple
overloaded new operator functions. This gives the programmer more flexibility in customizing memory
allocation for objects. For example:
Overloaded new or delete operators also provide Garbage Collection for class’s object.
Exception handling routine can be added in overloaded new operator function.
Sometimes you want operators new and delete to do something customized that the compiler-
provided versions don’t offer. For example, You might write a custom operator delete that
overwrites deallocated memory with zeros in order to increase the security of application data.
We can use realloc() function in new function to re-allocate memory dynamically.
39
Important Topics in C++
Overloaded new operator also enables programmers to squeeze some extra performance out of
their programs. For example, In a class, to speed up the allocation of new nodes, a list of deleted
nodes is maintained so that their memory can be reused when new nodes are allocated.In this case,
the overloaded delete operator will add nodes to the list of deleted nodes and the overloaded new
operator will allocate memory from this list rather than from the heap to speedup memory
allocation. Memory from the heap can be used when the list of deleted nodes is empty.
Overloaded new operator can accept additional arguments except size to be allocated.
In one class delete operator can be overloaded only once.
In one class new operator can be overloaded multiple times.
When we create object of the class with “new” operator the class overloaded new function will
get called with the object size as a parameter. e.g. CustomMemory object = new
CustomMemory.
Example
#include<iostream>
using namespace std;
class CustomMemory{
public:
}
void CustomMemory::operator delete(void* ptr)
{
cout<<"Custom memory de- allocation"<<endl;
free(ptr);
}
int main(){
40
Important Topics in C++
Example
#include<iostream>
using namespace std;
class CustomMemory{
int i;// size of int is 4 byte
public:
CustomMemory(){
cout<<"Constructor"<<"\n";
}
~CustomMemory(){
cout<<"Destructor"<<"\n";
}
//Overloaded new
void* operator new(size_t objectSize) {
cout<<"Custom memory allocation"<<"\n";
//Write allocation algorithm here
return malloc(objectSize);
}
//Overloaded 2 arguments new operator
void* operator new(size_t objectSize, int x) {
cout<<"Custom 2 argument memory allocation"<<"\n";
CustomMemory *ptr =(CustomMemory*)malloc(objectSize);
ptr->i = x;
return ptr;
}
//Overloaded delete
void operator delete(void* ptr) {
cout<<"Custom memory de- allocation"<<"\n";
free(ptr);
}
void Display(){
cout<<"Value of i ="<<i<<"\n";
}
};
int main(){
41
Important Topics in C++
42