Until now, in all our programs, we have only had as much memory available as we declared for our variables, having the size of all of them to be determined in the source code, before the execution of the program. But, what if we need a variable amount of memory that can only be determined during runtime? For example, in the case that we need some user input to determine the necessary amount of memory space.
The answer is dynamic memory, for which C++ integrates the operators new and delete.
In order to request dynamic memory we use the operator new. new is followed by a data type specifier and -if a sequence of more than one element is required- the number of these within brackets []. It returns a pointer to the beginning of the new block of memory allocated. Its form is:
pointer
= new type
pointer = new type [elements]
The first expression is used to allocate memory to contain one single element of type type. The second one is used to assign a block (an array) of elements of type type, where elements is an integer value representing the number of these. For example:
int * bobby;
bobby = new int [5];
In this case, the system dynamically assigns space for five elements of type int and returns a pointer to the first element of the sequence, which is assigned to bobby. Therefore, now, bobby points to a valid block of memory with space for five elements of type int.

The first element pointed by bobby can be accessed either with the expression bobby[0] or the expression *bobby. Both are equivalent as has been explained in the section about pointers. The second element can be accessed either with bobby[1] or *(bobby+1) and so on...
You could be wondering the difference between declaring a normal array and assigning dynamic memory to a pointer, as we have just done. The most important difference is that the size of an array has to be a constant value, which limits its size to what we decide at the moment of designing the program, before its execution, whereas the dynamic memory allocation allows us to assign memory during the execution of the program (runtime) using any variable or constant value as its size.
The dynamic memory requested by our program is allocated by the system from the memory heap. However, computer memory is a limited resource, and it can be exhausted. Therefore, it is important to have some mechanism to check if our request to allocate memory was successful or not.
C++ provides two standard methods to check if the allocation was successful:
One is by handling exceptions. Using this method an exception of type bad_alloc is thrown when the allocation fails. Exceptions are a powerful C++ feature explained later in these tutorials. But for now you should know that if this exception is thrown and it is not handled by a specific handler, the program execution is terminated.
This exception method is the default method used by new, and is the one used in a declaration like:
bobby = new int [5]; // if it fails an exception is thrown
The other method is known as nothrow, and what happens when it is used is that when a memory allocation fails, instead of throwing a bad_alloc exception or terminating the program, the pointer returned by new is a null pointer, and the program continues its execution.
This method can be specified by using a special object called nothrow as parameter for new:
bobby = new (nothrow) int [5];
In this case, if the allocation of this block of memory failed, the failure could be detected by checking if bobby took a null pointer value:
int * bobby;
bobby = new (nothrow) int [5];
if (bobby == 0) {
// error assigning memory. Take measures.
};
This nothrow method requires more work than the exception method, since the value returned has to be checked after each and every memory allocation, but I will use it in our examples due to its simplicity. Anyway this method can become tedious for larger projects, where the exception method is generally preferred. The exception method will be explained in detail later in this tutorial.
Since the necessity of dynamic memory is usually limited to specific moments within a program, once it is no longer needed it should be freed so that the memory becomes available again for other requests of dynamic memory. This is the purpose of the operator delete, whose format is:
delete pointer;
delete [] pointer;
The first expression should be used to delete memory allocated for a single element, and the second one for memory allocated for arrays of elements.
The value passed as argument to delete must be either a pointer to a memory block previously allocated with new, or a null pointer (in the case of a null pointer, delete produces no effect).
// rememb-o-matic
#include <iostream>
using namespace std;
int main ()
{
int i,n;
int * p;
cout << "How many numbers would you like to type? ";
cin >> i;
p= new (nothrow) int[i];
if (p == 0)
cout << "Error: memory could not be allocated";
else
{
for (n=0; n<i; n++)
{
cout << "Enter number: ";
cin >> p[n];
}
cout << "You have entered: ";
for (n=0; n<i; n++)
cout << p[n] << ", ";
delete[] p;
}
return 0;
}
Output
How many numbers would you like to type? 5
Enter number : 75
Enter number : 436
Enter number : 1067
Enter number : 8
Enter number : 32
You have entered: 75, 436, 1067, 8, 32,
Notice how the value within brackets in the new statement is a variable value entered by the user (i), not a constant value:
p= new (nothrow) int[i];
But the user could have entered a value for i so big that our system could not handle it. For example, when I tried to give a value of 1 billion to the "How many numbers" question, my system could not allocate that much memory for the program and I got the text message we prepared for this case (Error: memory could not be allocated). Remember that in the case that we tried to allocate the memory without specifying the nothrow parameter in the new expression, an exception would be thrown, which if it's not handled terminates the program.
It is a good practice to always check if a dynamic memory block was successfully allocated. Therefore, if you use the nothrow method, you should always check the value of the pointer returned. Otherwise, use the exception method, even if you do not handle the exception. This way, the program will terminate at that point without causing the unexpected results of continuing executing a code that assumes a block of memory to have been allocated when in fact it has not.
Operators new and delete are exclusive of C++. They are not available in the C language. But using pure C language, dynamic memory can also be used through the functions malloc, calloc, realloc and free, defined in the <cstdlib> header file, and since C++ is a superset of C, these functions are also available to C++ programmers.
The memory blocks allocated by these functions are not compatible with those returned by new, so each one should be manipulated with its own set of functions or operators.
We have already learned how groups of sequential data can be used in C++. But this is somewhat restrictive, since in many occasions what we want to store are not mere sequences of elements all of the same data type, but sets of different elements with different data types.
A data structure is a group of data elements grouped together under one name. These data elements, known as members, can have different types and different lengths. Data structures are declared in C++ using the following syntax:
struct
structure_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;
where structure_name is a name for the structure type, object_name can be a set of valid identifiers for objects that have the type of this structure. Within braces { } there is a list with the data members, each one is specified with a type and a valid identifier as its name.
The first thing we have to know is that a data structure creates a new type: Once a data structure is declared, a new type with the identifier specified as structure_name is created and can be used in the rest of the program as if it was any other type. For example:
struct product {
int weight; float price; } ; product apple; product banana, melon;
We have first declared a structure type called product with two members: weight and price, each of a different fundamental type. We have then used this name of the structure type (product) to declare three objects of that type: apple, banana and melon as we would have done with any fundamental data type.
Once declared, product has become a new valid type name like the fundamental ones int, char or short and from that point on we are able to declare objects (variables) of this compound new type, like we have done with apple, banana and melon.
Right at the end of the struct declaration, and before the ending semicolon, we can use the optional field object_name to directly declare objects of the structure type. For example, we can also declare the structure objects apple, banana and melon at the moment we define the data structure type this way:
struct product {
int weight; float price; } apple, banana, melon;
It is important to clearly differentiate between what is the structure type name, and what is an object (variable) that has this structure type. We can instantiate many objects (i.e. variables, like apple, banana and melon) from a single structure type (product).
Once we have declared our three objects of a determined structure type (apple, banana and melon) we can operate directly with their members. To do that we use a dot (.) inserted between the object name and the member name. For example, we could operate with any of these elements as if they were standard variables of their respective types:
apple.weight apple.price banana.weight banana.price melon.weight melon.price
Each one of these has the data type corresponding to the member they refer to: apple.weight, banana.weight and melon.weight are of type int, while apple.price, banana.price and melon.price are of type float.
Let's see a real example where you can see how a structure type can be used in the same way as fundamental types:
// example about structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std; struct movies_t { string title; int year; } mine, yours; void printmovie (movies_t movie); int main () { string mystr; mine.title = "2001 A Space Odyssey";
mine.year = 1968; cout << "Enter title: ";
getline (cin,yours.title);cout << "Enter year: ";
getline (cin,mystr); stringstream(mystr) >> yours.year; cout << "My favorite movie is:\n ";
printmovie (mine);cout << "And yours is:\n ";
printmovie (yours); return 0; } void printmovie (movies_t movie) { cout << movie.title;cout << " (" << movie.year << ")\n";
}OutputEnter title: Alien
Enter year: 1979 My favorite movie is: 2001 A Space Odyssey (1968) And yours is: Alien (1979)
The example shows how we can use the members of an object as regular variables. For example, the member yours.year is a valid variable of type int, and mine.title is a valid variable of type string.
The objects mine and yours can also be treated as valid variables of type movies_t, for example we have passed them to the function printmovie as we would have done with regular variables. Therefore, one of the most important advantages of data structures is that we can either refer to their members individually or to the entire structure as a block with only one identifier.
Data structures are a feature that can be used to represent databases, especially if we consider the possibility of building arrays of them:
// array of structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std; #define N_MOVIES 3
struct movies_t { string title; int year; } films [N_MOVIES]; void printmovie (movies_t movie); int main () { string mystr; int n; for (n=0; n<N_MOVIES; n++) {cout << "Enter title: ";
getline (cin,films[n].title);cout << "Enter year: ";
getline (cin,mystr); stringstream(mystr) >> films[n].year; } cout << "\nYou have entered these movies:\n";
for (n=0; n<N_MOVIES; n++) printmovie (films[n]); return 0; } void printmovie (movies_t movie) { cout << movie.title;cout << " (" << movie.year << ")\n";
}
Output
Enter title: Blade Runner
Enter year: 1982 Enter title: Matrix Enter year: 1999 Enter title: Taxi Driver Enter year: 1976 You have entered these movies: Blade Runner (1982) Matrix (1999) Taxi Driver (1976)
Like any other type, structures can be pointed by its own type of pointers:
struct movies_t {
string title; int year; }; movies_t amovie; movies_t * pmovie;
Here amovie is an object of structure type movies_t, and pmovie is a pointer to point to objects of structure type movies_t. So, the following code would also be valid:
pmovie = &amovie;
The value of the pointer pmovie would be assigned to a reference to the object amovie (its memory address).
We will now go with another example that includes pointers, which will serve to introduce a new operator: the arrow operator (->):
// pointers to structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std; struct movies_t { string title; int year; }; int main () { string mystr; movies_t amovie; movies_t * pmovie; pmovie = &amovie; cout << "Enter title: ";
getline (cin, pmovie->title);cout << "Enter year: ";
getline (cin, mystr); (stringstream) mystr >> pmovie->year; cout << "\nYou have entered:\n";
cout << pmovie->title;cout << " (" << pmovie->year << ")\n";
return 0; }OutputEnter title: Invasion of the body snatchers
Enter year: 1978 You have entered: Invasion of the body snatchers (1978)
The previous code includes an important introduction: the arrow operator (->). This is a dereference operator that is used exclusively with pointers to objects with members. This operator serves to access a member of an object to which we have a reference. In the example we used:
pmovie->title
Which is for all purposes equivalent to:
(*pmovie).title
Both expressions pmovie->title and (*pmovie).title are valid and both mean that we are evaluating the member title of the data structure pointed by a pointer called pmovie. It must be clearly differentiated from:
*pmovie.title
which is equivalent to:
*(pmovie.title)
And that would access the value pointed by a hypothetical pointer member called title. The following panel summarizes possible combinations of pointers and structure members:
|
Expression |
What is evaluated |
Equivalent |
|
a.b |
Member b of object a |
|
|
a->b |
Member b of object pointed by a |
(*a).b |
|
*a.b |
Value pointed by member b of object a |
*(a.b) |
Structures can also be nested so that a valid element of a structure can also be on its turn another structure.
struct movies_t {
string title; int year; }; struct friends_t { string name; string email; movies_t favorite_movie; } charlie, maria; friends_t * pfriends = &charlie;
After the previous declaration we could use any of the following expressions:
charlie.name maria.favorite_movie.title charlie.favorite_movie.year pfriends->favorite_movie.year
(where, by the way, the last two expressions refer to the same member).
C++ allows the definition of our own types based on other existing data types. We can do this using the keyword typedef, whose format is:
typedef existing_type new_type_name ;
where existing_type is a C++ fundamental or compound type and new_type_name is the name for the new type we are defining. For example:
typedef char C;
typedef unsigned int WORD; typedef char * pChar; typedef char field [50];
In this case we have defined four data types: C, WORD, pChar and field as char, unsigned int, char* and char[50] respectively, that we could perfectly use in declarations later as any other valid type:
C mychar, anotherchar, *ptc1; WORD myword; pChar ptc2; field name;
typedef does not create different types. It only creates synonyms of existing types. That means that the type of myword can be considered to be either WORD or unsigned int, since both are in fact the same type.
typedef can be useful to define an alias for a type that is frequently used within a program. It is also useful to define types when it is possible that we will need to change the type in later versions of our program, or if a type you want to use has a name that is too long or confusing.
Unions allow one same portion of memory to be accessed as different data types, since all of them are in fact the same location in memory. Its declaration and use is similar to the one of structures but its functionality is totally different:
union union_name { member_type1 member_name1; member_type2 member_name2; member_type3 member_name3; . . } object_names;
All the elements of the union declaration occupy the same physical space in memory. Its size is the one of the greatest element of the declaration. For example:
union mytypes_t {
char c; int i; float f; } mytypes;
defines three elements:
mytypes.c mytypes.i mytypes.f
each one with a different data type. Since all of them are referring to the same location in memory, the modification of one of the elements will affect the value of all of them. We cannot store different values in them independent from each other.
One of the uses a union may have is to unite an elementary type with an array or structures of smaller elements. For example:
union mix_t {
long l; struct { short hi; short lo; } s; char c[4]; } mix;
defines three names that allow to access the same group of 4 bytes: mix.l, mix.s and mix.c and which we can use according to how we want to access these bytes, as if they were a single long-type data, as if they were two short elements or as an array of char elements, respectively. I have mixed types, arrays and structures in the union so that you can see the different ways that we can access the data. For a little-endian system (most PC platforms), this union could be represented as:

The exact alignment and order of the members of a union in memory is platform dependant. Therefore be aware of possible portability issues with this type of use.
In C++ we have the option to declare anonymous unions. If we declare a union without any name, the union will be anonymous and we will be able to access its members directly by their member names. For example, look at the difference between these two structure declarations:
|
structure with regular union |
structure with anonymous union |
struct { char title[50]; char author[50]; union { float dollars; int yens; } price;} book; |
struct { char title[50]; char author[50]; union { float dollars; int yens; };} book; |
The only difference between the two pieces of code is that in the first one we have given a name to the union (price) and in the second one we have not. The difference is seen when we access the members dollars and yens of an object of this type. For an object of the first type, it would be:
book.price.dollars book.price.yens
whereas for an object of the second type, it would be:
book.dollars book.yens
Once again I remind you that because it is a union and not a struct, the members dollars and yens occupy the same physical space in the memory so they cannot be used to store two different values simultaneously. You can set a value for price in dollars or in yens, but not in both.
Enumerations create new data types to contain something different that is not limited to the values fundamental data types may take. Its form is the following:
enum enumeration_name { value1, value2, value3, . .} object_names;
For example, we could create a new type of variable called color to store colors with the following declaration:
enum colors_t {black, blue, green, cyan, red, purple, yellow, white};
Notice that we do not include any fundamental data type in the declaration. To say it somehow, we have created a whole new data type from scratch without basing it on any other existing type. The possible values that variables of this new type color_t may take are the new constant values included within braces. For example, once the colors_t enumeration is declared the following expressions will be valid:
colors_t mycolor; mycolor = blue; if (mycolor == green) mycolor = red;
Enumerations are type compatible with numeric variables, so their constants are always assigned an integer numerical value internally. If it is not specified, the integer value equivalent to the first possible value is equivalent to 0 and the following ones follow a +1 progression. Thus, in our data type colors_t that we have defined above, black would be equivalent to 0, blue would be equivalent to 1, green to 2, and so on.
We can explicitly specify an integer value for any of the constant values that our enumerated type can take. If the constant value that follows it is not given an integer value, it is automatically assumed the same value as the previous one plus one. For example:
enum months_t { january=1, february, march, april,
may, june, july, august, september, october, november, december} y2k;
In this case, variable y2k of enumerated type months_t can contain any of the 12 possible values that go from january to december and that are equivalent to values between 1 and 12 (not between 0 and 11, since we have made january equal to 1).
A class is an expanded concept of a data structure: instead of holding only data, it can hold both data and functions.
An object is an instantiation of a class. In terms of variables, a class would be the type, and an object would be the variable.
Classes are generally declared using the keyword class, with the following format:
lass class_name { access_specifier_1: member1; access_specifier_2: member2; ... } object_names;
Where class_name is a valid identifier for the class, object_names is an optional list of names for objects of this class. The body of the declaration can contain members, that can be either data or function declarations, and optionally access specifiers.
All is very similar to the declaration on data structures, except that we can now include also functions and members, but also this new thing called access specifier. An access specifier is one of the following three keywords: private, public or protected. These specifiers modify the access rights that the members following them acquire:
By default, all members of a class declared with the class keyword have private access for all its members. Therefore, any member that is declared before one other class specifier automatically has private access. For example:
class CRectangle {
int x, y; public: void set_values (int,int); int area (void); } rect;
Declares a class (i.e., a type) called CRectangle and an object (i.e., a variable) of this class called rect. This class contains four members: two data members of type int (member x and member y) with private access (because private is the default access level) and two member functions with public access: set_values() and area(), of which for now we have only included their declaration, not their definition.
Notice the difference between the class name and the object name: In the previous example, CRectangle was the class name (i.e., the type), whereas rect was an object of type CRectangle. It is the same relationship int and a have in the following declaration:
int a;
where int is the type name (the class) and a is the variable name (the object).
After the previous declarations of CRectangle and rect, we can refer within the body of the program to any of the public members of the object rect as if they were normal functions or normal variables, just by putting the object's name followed by a dot (.) and then the name of the member. All very similar to what we did with plain data structures before. For example:
rect.set_values (3,4); myarea = rect.area();
The only members of rect that we cannot access from the body of our program outside the class are x and y, since they have private access and they can only be referred from within other members of that same class.
Here is the complete example of class CRectangle:
// classes example
#include <iostream>
using namespace std; class CRectangle { int x, y; public: void set_values (int,int); int area () {return (x*y);} }; void CRectangle::set_values (int a, int b) { x = a; y = b; } int main () { CRectangle rect; rect.set_values (3,4);cout << "area: " << rect.area();
return 0; }Outputarea: 12
The most important new thing in this code is the operator of scope (::, two colons) included in the definition of set_values(). It is used to define a member of a class from outside the class declaration itself.
You may notice that the definition of the member function area() has been included directly within the definition of the CRectangle class given its extreme simplicity, whereas set_values() has only its prototype declared within the class, but its definition is outside it. In this outside declaration, we must use the operator of scope (::) to specify that we are defining a function that is a member of the class CRectangle and not a regular global function.
The scope operator (::) specifies the class to
which the member being declared belongs, granting exactly the same scope properties
as if this function definition was directly included within the class
definition. For example, in the function set_values() of the previous code, we have been able
to use the variables x
and y, which are
private members of class CRectangle,
which means they are only accessible from other members of their class.
The only difference between defining a class member function completely within
its class and to include only the prototype and later its definition, is that
in the first case the function will automatically be considered an inline
member function by the compiler, while in the second it will be a normal
(not-inline) class member function, which in fact supposes no difference in
behavior.
Members x and y have private access (remember that if nothing else is said, all members of a class defined with keyword class have private access). By declaring them private we deny access to them from anywhere outside the class. This makes sense, since we have already defined a member function to set values for those members within the object: the member function set_values(). Therefore, the rest of the program does not need to have direct access to them. Perhaps in a so simple example as this, it is difficult to see an utility in protecting those two variables, but in greater projects it may be very important that values cannot be modified in an unexpected way (unexpected from the point of view of the object).
One of the greater advantages of a class is that, as any other type, we can declare several objects of it. For example, following with the previous example of class CRectangle, we could have declared the object rectb in addition to the object rect:
// example: one class, two objects
#include <iostream>
using namespace std; class CRectangle { int x, y; public: void set_values (int,int); int area () {return (x*y);} }; void CRectangle::set_values (int a, int b) { x = a; y = b; } int main () { CRectangle rect, rectb; rect.set_values (3,4); rectb.set_values (5,6);cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
return 0; }Outputrect area: 12
rectb area: 30
In this concrete case, the class (type of the objects) to which we are talking about is CRectangle, of which there are two instances or objects: rect and rectb. Each one of them has its own member variables and member functions.
Notice that the call to rect.area() does not give the same result as the call to rectb.area(). This is because each object of class CRectangle has its own variables x and y, as they, in some way, have also their own function members set_value() and area() that each uses its object's own variables to operate.
That is the basic concept of object-oriented programming: Data and functions are both members of the object. We no longer use sets of global variables that we pass from one function to another as parameters, but instead we handle objects that have their own data and functions embedded as members. Notice that we have not had to give any parameters in any of the calls to rect.area or rectb.area. Those member functions directly used the data members of their respective objects rect and rectb.
Objects generally need to initialize variables or assign dynamic memory during their process of creation to become operative and to avoid returning unexpected values during their execution. For example, what would happen if in the previous example we called the member function area() before having called function set_values()? Probably we would have gotten an undetermined result since the members x and y would have never been assigned a value.
In order to avoid that, a class can include a special function called constructor, which is automatically called whenever a new object of this class is created. This constructor function must have the same name as the class, and cannot have any return type; not even void.
We are going to implement CRectangle including a constructor:
// example: class constructor
#include <iostream>
using namespace std; class CRectangle { int width, height; public: CRectangle (int,int); int area () {return (width*height);} }; CRectangle::CRectangle (int a, int b) { width = a; height = b; } int main () { CRectangle rect (3,4); CRectangle rectb (5,6);cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
return 0; }Outputrect area: 12
rectb area: 30
As you can see, the result of this example is identical to the previous one. But now we have removed the member function set_values(), and have included instead a constructor that performs a similar action: it initializes the values of x and y with the parameters that are passed to it.
Notice how these arguments are passed to the constructor at the moment at which the objects of this class are created:
CRectangle rect (3,4); CRectangle rectb (5,6);
Constructors cannot be called explicitly as if they were regular member functions. They are only executed when a new object of that class is created.
You can also see how neither the prototype nor the later constructor declaration includes a return value; not even void.
The destructor fulfills the opposite functionality. It is automatically called when an object is destroyed, either because its scope of existence has finished (for example, if it was defined as a local object within a function and the function ends) or because it is an object dynamically assigned and it is released using the operator delete.
The destructor must have the same name as the class, but preceded with a tilde sign (~) and it must also return no value.
The use of destructors is especially suitable when an object assigns dynamic memory during its lifetime and at the moment of being destroyed we want to release the memory that the object was allocated.
// example on constructors and destructors
#include <iostream>
using namespace std; class CRectangle { int *width, *height; public: CRectangle (int,int); ~CRectangle (); int area () {return (*width * *height);} }; CRectangle::CRectangle (int a, int b) { width = new int; height = new int; *width = a; *height = b; } CRectangle::~CRectangle () { delete width; delete height; } int main () { CRectangle rect (3,4), rectb (5,6);cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
return 0; }Outputrect area: 12
rectb area: 30
Like any other function, a constructor can also be overloaded with more than one function that have the same name but different types or number of parameters. Remember that for overloaded functions the compiler will call the one whose parameters match the arguments used in the function call. In the case of constructors, which are automatically called when an object is created, the one executed is the one that matches the arguments passed on the object declaration:
// overloading class constructors
#include <iostream>
using namespace std; class