Our Recommendation for You Search your Query, You can find easily. for example search by book name or course name or any other which is related to your education

Followers

CS 201 Lecture No 28 Video



Lecture Handout
Introduction to Programming
Lecture No. 28


Reading Material

Deitel & Deitel - C++ How to Program   Chapter 7
       7.6, 7.8 

Summary


• Lecture Overview
• Memory Allocation in C
• Memory Allocation in C++
• new Operator and Classes
• Example Program 1
• Classes and Structures in C++
• new Operator and Constructors
• delete Operator and Classes
• Example Program 2
• new, delete outside Constructors and Destructors
• main() Function and Classes
• Class Abstraction
• Messages and Methods
• Classes to Extend the Language
• Tips

Lecture Overview
In the previous lectures, we have been discussing about Classes, Objects, Constructors
and Destructors. In this lecture we will take them further while discussing Memory
Allocation.

- We’ll see how the memory allocation is done in C++, while discussing memory
allocation in C? - How C++ style is different from the C-style of allocation discussed earlier?
- What are the advantages of C++ approach as compared to that of C?

Memory Allocation in C 
Before further proceeding with the concept of memory, it is better to know what else we
can create with classes besides objects.

Recapturing of the concept of ‘structures’ can help us to move forward. Consider the
following statement.

struct   abc
{
int   integer;
float   floatingpoint; 
};

We could have declared a structure object as: 
struct   abc   xyz; // Declared an object of structure type

and access data members inside structure by using dot operator (“.”) as: 
xyz.integer   =   2134;
xyz.floatingpoint   =   234.34;

Similarly, we could have a pointer to a structure object as:
struct   abc*   abcPtr; // Declared a pointer of a structure type
abcPtr   =   xyz; // Pointer is pointing to xyz object now

We can access the individual data member as:
abcPtr->integer   =   2134;
abcPtr->floatingpoint   =   234.34;

We can have pointers to different data structures, similarly, pointer to a class object. Here
we are going to discuss about Pointers, Classes and Objects.

Let’s start by talking about memory allocation. We introduced few functions of memory
allocation in C: malloc(), calloc() and realloc(). Using these functions, memory is
allocated while the program is running. This means while writing your program or at
compile time, you don’t need to know the size of the memory required. You can allocate
memory at runtime (dynamically) that has many benefits. The classic example will be of
an array declared to store a string. If the length of the actual string is lesser than the size
of the array, then the part that remains unoccupied will be wasted. Suppose we declare an
array of length 6 to contain student name. It is alright if the student name is let’s say
Jamil but what will happen for the student named Abdul Razzaq. This is a case where
dynamic memory allocation is required.  In C language, the region of memory allocated at runtime is called heap. However, in 
C++, the region of available memory is called free store. We have different functions to
manipulate memory in both C and C++.
You know that while using malloc(), we have to tell the number of bytes required from
memory like: 
malloc(number of bytes required to be allocated);

Sometimes, we also do a little manipulation while calculating the number of bytes
required to be allocated: i.e.
malloc( 10 * ( sizeof(int) ) );

The malloc() returns a void pointer (void *). A pointer that points to a void type of
memory. So in order to use this memory, we have to cast it to our required type. Suppose,
we want to use it for ints. For this purpose, you will cast this returned void pointer to int
* and then assign it to an int * before making its further use. The following code is an
example of malloc() usage.

class Date
{
 public:
  Date( ) ;
  Date(int month, int day, int year);
   ~Date ( ) ;
setMonth( int month ) ;
setDay( int day ) ;           
     setYear( int year ) ; 
  int getDay ( ) ;                       
       int getMonth ( ) ;
     int getYear ( ) ;
  setDate(int day, int month, int year);
 private:
     int month, day, year;           
};

Date  *datePtr;     // Declared a pointer of Date
type.
int   i;
datePtr   =   (Date *) malloc( sizeof( Date ) ); // Used malloc() to allocate
memory 
i  =   datePtr->getMonth();         // Returns undefined month value

So there is some house-keeping involved during the use of this function. We have to
determine the number of bytes required to be allocated and cast the returned void pointer
to our required type and then assign it to a variable pointer. Lastly, the memory returned
from this function is un-initialized and it may contain garbage.
 The contrasting function used to free the allocated memory using malloc() is free()
function. As a programmer, if you have allocated some memory using malloc(), it is your
responsibility to free it. This responsibility of de-allocation will be there while using C++
functions. But these new functions are far easier to use and more self-explanatory.

Memory Allocation in C++
The memory allocation in C++ is carried out with the use of an operator called new.
Notice that new is an operator while the malloc() was a function. Let’s see the syntax of
new operator through the following example.

 new   int;

In the above statement, the new operator is allocating memory for an int and returns a
pointer of int type pointing to this region of memory. So this operator not only allocated
required memory but also spontaneously returned a pointer of required type without
applying a cast.

In our program,
 we can write it as:
int   *iptr;
iptr   =   new   int;

So while using new operator, we don’t need to supply the number of bytes allocated.
There is no need to use the sizeof operator and cast the pointer to the required type.
Everything is done by the new operator for us. Similarly, new operator can be used for
other data types like char, float and double etc.

The operator to free the allocated memory using new operator is delete. So whenever, we
use new to allocate memory, it will be necessary to make use of ‘delete’ to de-allocate
the allocated memory.
 delete   iptr;

The delete operator frees the allocated memory that is returned back to free store for
usage ahead.

What if we want to allocate space for any array? It is very simple. Following is the
syntax:
new data_type [number_of_locations];

For example, we want to allocate an array of 10 ints dynamically. Then the statement
will be like this:
int   *iptr;
iptr   =   new  int[10];

What it does is, it tries to occupy memory space for 10 ints in memory. If the memory is
occupied successfully, it returns int * that is assigned to iptr. 

Whenever we allocate memory dynamically, it is allocated from free store. Now we will
see what happens if the memory in the free store is not sufficient enough to fulfill the
request. malloc() function returns NULL pointer if the memory is not enough. In C++, 0
is returned instead of NULL pointer. Therefore, whenever we use new to allocate
memory, it is good to check the returned value against 0 for failure of the new operator.

Remember, new is an operator,it is not a function. Whenever we use new, we don’t use
parenthesis with it, no number of bytes or sizeof operator is required and no cast is
applied to convert the pointer to the required type.

delete operator is used to free the memory when the allocation is done by using new as
shown below:
int   *iptr;
iptr   =   new   int [10]; // Memory for 10 ints is allocated dynamically.
delete   iptr;  // Allocated is freed and returned to the free store.

Can we apply the concept of dynamic memory allocation/deallocation while using
new/delete with classes and objects? The answer is obviously yes.


new Operator and Classes
 As we declare a pointer to a primitive datatype, similarly, we can have a pointer to a
class object. 

Date   *dptr;    // dptr is a pointer to an object of type Date.
Now, we create the object using the new operator.
Remember, the basic definition of a class
i.e. it is a user-defined data type. In other words, the language has been extended to a
programmer to have user defined data types.



Whatever amount of memory is required for a Date object, is allocated from the free
store. A pointer to of Date type is returned back and assigned to the dptr pointer variable.
Is this all what new is doing? If it is so, can we use malloc() function by providing
number of bytes required for Date object with the help of  sizeof operator. The answer to
this question lies in the further discussion.

Date   mydate;
cout   <<   sizeof (mydate);

As discussed in the last lecture, whenever we instantiate an object of a class, the data
members are allocated for each object. However, the member functions occupy a
common region in memory for all objects of a class. Therefore, sizeof operator returns
the size of the data-members storage excluding the member functions part. In the above
statement, the sizeof operator returns the sum of the sizes of three integers day, month
and year, declared in the Date class.

The amount of memory allocated in the above statement using new (dptr   =   new 
Date;) is same as reflected in the  following statement:
 dptr   =   (Date *)  malloc( sizeof(Date) );
The new operator in the above statement ( dptr   =   new  Date;) has automatically
determined the size of the Date object and allocated memory before returning a pointer of
Date * type. Is this all what new is doing? Actually, it is doing more than this. It is also
creating an object of type Date. C functions like malloc() do nothing for object creation.
Rather these C functions allocate the required number of bytes and return a void *
pointing to the allocated memory where the memory might contain garbage. But the new
operator not only allocates the memory after automatically determining the size of the
object but also creates an object before returning a pointer of object’s class type.
Additionally, within the call to the new operator, the memory assigned to the created
object with the use of new operator can be initialized with meaningful values instead of
garbage (think of C functions like malloc() ).

How the data members are initialized with meaningful values? Actually, a constructor is
called whenever an object is created. Inside the constructor, individual data members can
be initialized. The C++ compiler generates a default constructor for a class if the
programmer does not provide it. But the default constructor does not perform any data
members initialization. Therefore, it is good practice that whenever you write a class, use
a constructor function to initialize the data members to some meaningful values. 

Whenever new operator is used to create an object, following actions are performed by it:
- It automatically determines the size of the memory required to store that object,
leaving no need for the use of sizeof operator.
- Calls the constructor of the Class, where the programmers normally write
initialization code. - Returns pointer of the class type that means no casting is required.

Hence, new operator is extremely useful, powerful and a good way of allocating memory.

Let’s suppose, we want to allocate space for 10 ints as under:

int   * iptr;
iptr   =   new   int [10];

This new statement allocates contiguous space for an array of 10 ints and returns back
pointer to the first int. Can we do this operation for objects of a class? The answer to this
question is yes. The syntax in this case will be identical. To create an array of 10 objects
of Date type, following code is written:

Date   * dptr;
dptr   =   new   Date [10];
int   day   =   dptr->getDay();
Here the new operator allocates memory for 10 Date objects. It calls the default or
parameter-less constructors of the Date class and returns the pointer to the first object,
assigned to the dptr variable. Arrow operators (->) is used while accessing functions or
data members from the pointer variable.


Example Program 1 
/* Following program demonstrates the new operator. This program has the problem of
memory leak because delete operator is not called for the allocated memory. */

#include   <iostream.h>

class   MyDate
{
    public:     // public members are below
     
       /* Parameterless constructor of MyDate class */
       MyDate( )
        {
                cout   <<   "\n Parameterless constructor called ...";
                month   =   day   =   year   =   0;       //  all data member initialized to 0
        }
       
      /* Parameterized constructor of MyDate class. It assigns the parameter values  to the
……..data members of the class */
       MyDate(int month, int day, int year)
        {
                cout   <<   "\n Constructor with three int parameters called ..."; 
                this->month   =   month;   // Notice the use of arrow operator ( -> )
                this->day   =   day;
                this->year   =   year;
        }
     
       /* Destructor of the MyDate class */
       ~MyDate ( )
       {
              cout   <<   "\n Destructor called ...";
       }
       
 /* Setter function for the month data member. It assigns the parameter value to
 the month data member */
       void setMonth ( int month )
       {
              this->month   =   month;
       }
     
        /* Setter function for the day data member. It assigns the parameter value to the
            day data member */
       void setDay ( int day )
       {
              this->day   =   day;
       }
     
        /* Setter function for the year data member. It assigns the parameter value to the
            year data member */
       void setYear ( int year )
       {
              this->year   =   year;
       }
     
       /* Getter function for the day data member. It returns the value of the day data
           member */
       int getDay ( )
       {
              return   this->day;
       }
     
       /* Getter function for the month data member. It returns the value of the
            month data member */
       int getMonth ( )
       {               return   this->month;
       }
     
       /* Getter function for the year data member. It returns the value of the year data
           member */
       int getYear ( )
       {
              return   this->year;
       }
     
       /* A function to set all the attributes (data members) of the Date object */
       void setDate ( int day, int month, int year )
       {
              this->day   =   day;
              this->month   =   month;
              this->year   =   year;
       }
     
   private:                  // private members are below 
      int   month,   day,   year;           
};

main(void)
{
    MyDate   *dptr;                          // Declared a pointer dptr to MyPointer class object
    dptr   =   new   MyDate [10];     // Created 10 objects of MyDate and assigned the
                                                       //  pointer to the first object to dptr pointer variable.

// delete should have been called here before the program terminates.
}


The output of this example program is as follows:
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...

Notice that the constructor is called 10 times with 10 new calls but there is no call to
destructor. What is the reason? The objects are created with the new operator on free store, they will not be destroyed and memory will not be de-allocated unless we call
delete operator to destroy the objects and de-allocate memory. So memory allocated on
free store is not de-allocated in this program and that results in memory leak. There is
another point to be noted in this example program, which is not relevant to our topics of
discussion today that all the functions are requested to be inline automatically as the
functions are defined within the class body.

Classes and Structures in C++
Structures and classes in C++ are quite similar. C++ structure is declared with the same
keyword struct as in C.  Unlike C structure, C++ structure can have data and member
functions. The difference between class and structure is of visibility. Every data member
or function written inside the structure is public (visible from outside) by default unless
declared otherwise. Similarly, everything declared inside a class is private (not visible
from outside) by default unless declared as public.
While writing classes, good programming practice is to write private keyword explicitly,
despite the fact that this is the default behavior. Similarly, while writing structures, it is
good to write the public keyword explicitly. This averts confusion and increases
readability.
Another good practice is to write public or private keywords only once in the class or
structure declaration, though there is no syntactical or logical problem in writing them
multiple times.
Also remember while writing a class or a structure that once a keyword is written, say
public, the declarations falling below this keyword will be public until the private
keyword is mentioned.
There is another keyword protected. We are not using this keyword in this course because
that deals with inheritance that is a part of Object Oriented Programming, a separate
course.

new Operator and Constructors
It is clear that whenever new operator is called to create an object, the constructor is also
called for that object. What will happen if we have to call new from inside a constructor
function. Can we do that? The answer is definitely yes. There are times when we have to
do dynamic memory allocation or create new objects from inside a constructor. For
example, we have a Student class with attributes i.e. roll number, age, height and name. The attributes like roll number, age and height can be contained in ints or floats
but the name attribute will require a string. Because of the nature of this attribute (as it
can have different lengths for different students), it is better to use dynamic memory
allocation for this. So we will use new operator from within the constructor of Student
class to allocate memory for the name of the student.

We know whenever we use new to allocate memory, it is our responsibility to de-allocate
the memory using the delete operator. Failing which, a memory leak will happen.
Remember, the memory allocated from free store or heap is a system resource and is not
returned back to the system ( even if the allocating program terminates ) unless explicitly
freed using delete or free operators.

Now, we will see how the delete works for objects and what is the syntax.

delete Operator and Classes
As in our Student class, as we will be allocating memory from within the constructor of
it. Therefore, there is a need to call delete to de-allocate memory. What is the appropriate
location inside the class Student to call delete operator to de-allocate memory? In
normal circumstances, the location is the destructor of a class (Student class’s destructor
in this case). The destructor is used to de-allocate memory because it is called when the
object is no more needed or going to be destroyed from the program’s memory. So this is
the real usefulness of destructors that these are used to release the system resources
including memory occupied by the objects.
As a thumb rule , whenever there is a pointer data member inside our class and pointer is
being used by allocating memory at runtime. It is required to provide a destructor for that
class to release the allocated memory. A constructor can be overloaded but not a
destructor. So  there is only one destructor for a class. That one destructor of a class must
do house keeping before the object is destroyed. Normal data members int, char, float
and double, not allocated using malloc() or new operator, don’t need to be de-allocated
using free() or delete. These are automatically destroyed.

Let’s be sure that free() is used with malloc() function while delete operator with new
operator. Normally, new will be called in a constructor. However, delete will be called in
the destructor.


Example Program 2 
/* Following program demonstrates the new and delete operators. It deallocates the
memory properly before terminating. */

#include   <iostream.h>


class   MyDate
{
    public:     //public members are below
     
       /* Parameterless constructor of MyDate class */
       MyDate( )
        {
                cout   <<   "\n Parameterless constructor called ...";
                month   =   day   =   year   =   0;       //  all data member initialized to 0
        }
       
      /* Parameterized constructor of MyDate class. It assigns the parameter values  to the
……..data members of the class */
       MyDate(int month, int day, int year)
        {
                cout   <<   "\n Constructor with three int parameters called ...";
                this->month   =   month;   // Notice the use of arrow operator ( -> )
                this->day   =   day;
                this->year   =   year;
        }
     
       /* Destructor of the MyDate class */
       ~MyDate ( )
       {
              cout   <<   "\n Destructor called ...";
       }
       
 /* Setter function for the month data member. It assigns the parameter value to
 the month data member */
       void setMonth ( int month )
       {
              this->month   =   month;
       }
     
        /* Setter function for the day data member. It assigns the parameter value to the
            day data member */
       void setDay ( int day )
       { 
              this->day   =   day;
       }
     
        /* Setter function for the year data member. It assigns the parameter value to the
            year data member */
       void setYear ( int year )


       {
              this->year   =   year;
       }
     
       /* Getter function for the day data member. It returns the value of the day data
           member */
       int getDay ( )
       {
              return   this->day;
       }
     
       /* Getter function for the month data member. It returns the value of the
            month data member */
       int getMonth ( )
       {
              return   this->month;
       }
     
       /* Getter function for the year data member. It returns the value of the year data
           member */
       int getYear ( )
       {
              return   this->year;
       }
     
       /* A function to set all the attributes (data members) of the Date object */
       void setDate ( int day, int month, int year )
       {
              this->day   =   day;
              this->month   =   month;
              this->year   =   year;
       }
     
   private:                  // private members are below
      int   month,   day,   year;           
};

main(void)
{
    MyDate   *dptr;                          // Declared a pointer dptr to MyPointer class object
    dptr   =   new   MyDate [10];     // Created 10 objects of MyDate and assigned the
                                                       //  pointer to the first object to dptr pointer variable.

    delete   [] dptr;                           // Deleted (freed) the assigned memory to the objects
}

The output of this example program is as follows:
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Parameterless constructor called ...
Destructor called ...
Destructor called ...
Destructor called ...
Destructor called ...
Destructor called ...
Destructor called ...
Destructor called ...
Destructor called ...
Destructor called ...
Destructor called ...

It is very clear from the output that the destructor for all the objects is called to avert any
memory leak. The memory allocated using new operator is being de-allocated using the
delete operator. Notice the syntax of delete while de-allocating an array, the brackets ([])
precedes the name of the array after the delete operator.


new, delete outside Constructors and Destructors
Can new be called from some location other than constructor? The answer is yes and we
usually need to do that. Suppose, we have an object of Student class. The name of the
student is: Abdul Khaliq. So for the name attribute, the space is allocated dynamically to
store the string Abdul Khaliq. When our program is running and we have already
allocated space for the Abdul Khaliq string using the new operator, after sometime, we
are required to increase the size of the string. Let’s say we want to change the string to
Abdul Khaliq Khan now.
So what we can do, without destroying this student object: 
De-allocate the name previously occupied string using the delete operator, determine the
size of memory required with the help of strlen() function, allocate the memory required
for the new string Abdul Khaliq Khan using the new operator and finally assign the
returned pointer to the name data member.

Hence, we can call new and delete operators, not only outside the class to create objects
but also within the class. The objects of the same class can have different sizes of memory space like in case of objects of Student class, student 1 object can be of one size
and student 2 object can be of an another size, primarily varying because of string name.
But independent of this object size, the destructor of the object remains the same and deallocates
memory
for different
objects
regardless of their different
sizes.
delete
operator

is
used
from
within
the
destructor
to deallocate
the
memory.
We
call
delete
operator
to

determine
the size
of
the memory
required
to be
de-allocated
and
only
provide
it a pointer

pointing
to it.



Please
note that
C functions
like malloc()
and
free()
functions
can also be used
from

within
C++
code.
But while
writing
classes
inside
C++ code,
we
prefer
to use
new
and

delete
operators
as
they
are
designed
to work
with classes
and
objects.





main() Function and Classes
We used to discuss about main() function a lot while writing our programs in C. You
might have noticed that while discussing about classes and objects, we are not talking
about the main() function. This does not mean that main() function is not there in C++. It
is there but it does not contain as much code in C++ . But as you go along and write your
own classess, you will realize that almost 90% of your program’s code lies inside the
class definitions. So firstly we write our classes and main() function is written after
classes have been defined. That is why the main() function is very small. Our example
programs clearly depict this fact.


Class Abstraction
Whenever we write a class, we think about its users. Who are the ones going to use this
class? The users are not only the main() function of the program but also our colleagues
around us. Remember, we only expose interface to our users and not the class
implementation. All what users need to know is provided in the interface, the methods
signatures and what can be achieved by calling that method. The users do not need to
know how the functions or interfaces are implemented, what are the variables, how is the
data inside and how is it being manipulated, it is abstract to the users.


Messages and Methods
When we create an object, we ask that object to do something by calling a function. This
way of asking objects in Windows operating system is called Messaging or in other
words function calling is sending a message to the object. Sending a message is a
synonym of calling a method of an object. The word ‘method’ is from the fact that it is a
way of doing something. So the whole program is sending messages and getting
responses back. It is a different way of looking at things.
Notice lot of things have been repeated in this lecture many times, the reason is that now,
you are required to think differently, more in terms of classes and objects. There are lots
of exciting things coming up to be covered later.


Classes to Extend the Language
We know that in C, there is no data type for complex numbers. Therefore, we needed to
define our own class for complex numbers. We might use double data type for real and
imaginary parts. From basic Mathematics, we also know that whenever two complex
numbers are added, real part of one complex number is added into the real part of other
complex number and imaginary part of one complex number is added into the imaginary
part of other complex number. We might write a function for this operation and might
call this as cadd(). We might also write other functions for multiplication and division. In
C++, the operators like ‘+’, ‘*’ and ‘/’ can be overloaded, therefore, we could overload
these operators for complex numbers, so that we could easily use these ordinary addition,
multiplication, and division operators for complex numbers. Actually, we don’t need to
write this class on our own because this is already been provided in many C++ libraries.

Remember, there is no primitive data type in C++ for complex numbers but a class has
been written as part of the many C++ libraries. Moral of the above paragraph is; by using
user defined data types i.e., classes, we can now really extend the language.


Tips
- Classes are one way of extending the C++ language.

- Whenever new operator is used, no number of bytes or sizeof operator is required and
no cast is applied to convert the pointer to the required type.

- Whenever new operator is called to create an object, the constructor is also called for
that object. It is a good practice that whenever you write a class, use a constructor
function to initialize the data members to some meaningful values.

- The usual practice is to use constructor to allocate memory or system resources and
destructors to de-allocate or return the resources back to the system.

- In C language, the region of memory allocated at runtime is called heap. However, in

C++, the region of available memory is called free store. There are different
functions in C and C++ to manipulate memory at runtime. However, all C functions
are useable in C++ code.
- The memory allocated from free store or heap is a system resource and is not
returned back to the system unless explicitly freed using delete or free operators. - If the memory in the free store is not sufficient enough to fulfill the request, malloc()
function returns NULL pointer. Similarly, the new function returns 0 in case the
request could not be fulfilled. 

- Whenever we use new operator, the returned value from the new should be checked
against 0 for any possible failures. 

- While writing classes, good programming practice is to write private keyword
explicitly, despite the fact that this is the default scope. Additionally, the good
practice is to write public or private keywords only once in the class or structure
definitions, though there is no syntactical or logical problems in writing them
multiple times.