chapter 11 mechanisms for developing flexible list representations pointers and dynamic memory
DESCRIPTION
Usefulness Necessary for dynamic objects Objects whose memory is acquired during program execution as the result of a specific program request Dynamic objects can survive the execution of the function in which they are acquired Dynamic objects enable variable-sized lists, for example, the vector class The acquired memories of most programs can not be determined in compiling phase of program, but at run timeTRANSCRIPT
Chapter 11Chapter 11
Mechanisms for developing flexible list representations
Pointers and dynamic memory
L-values R-values pointer types null address dereference operator * indirect members selector -> address operator & pointer assignment indirect assignment pointers as parameters pointers to pointers constant pointers pointers to constants arrays and pointers
pointers to function dynamic objects free store operators new and delete exception handling dangling pointers memory leak destructors copy constructor member assignment this pointer qualifier const
Key Concepts:Key Concepts:
Usefulness
Necessary for dynamic objects Objects whose memory is acquired during
program execution as the result of a specific program request Dynamic objects can survive the
execution of the function in which they are acquired
Dynamic objects enable variable-sized lists, for example, the vector class
The acquired memories of most programs can not be determined in compiling phase of program, but at run time
Memory Memory and its addressaddress
Memory Memory and its address addressMain board
Graphics adapterSound blaster
Hard disk driver
Main memory
CPU
Memory Memory and its address address
System Bus
CPU Memory
Output
device
Input devic
e
Memory Memory and its address addressSystem bus transfers the data information, address information and control information Data bus transfers the data information Address bus transfers the address
information Control bus transfers the control information
32 bits address bus has an ability of addressing memory space of 4GB From 0x00000000 to 0xFFFFFFFF
Memory Memory and its address addressMain memory
0x00000001
0x00000000
0x00000002
0x00000003
0x7FFFFFFF
0xFFFFFFFD
0xFFFFFFFE0xFFFFFFFF
NULL address
...
......
L-value and R-valueL-value expressions
Represent objects that can be evaluated and modified
R-value expressions Represent objects that can only be evaluated
Considerint a;vector<int> b(3);int c[3];a = 1; // a: lvaluec[0] = 2*a + b[0]; // c[0], a, b[0]: lvalues
Observation Not all lvalues are the names of objects
Pointer basics
Pointer Object whose value represents the location of
another object In C++ there are pointer types for each type of
object Pointers to int objects Pointers to char objects Pointers to RectangleShape objects
Even pointers to pointers Pointers to pointers to int objectsNormally a pointer is an unsigned integer, its size is
variable with the operation system and compiler A 32 bits pointer occupies itself 4 bytes of memory A 16 bits pointer occupies itself 2 bytes of memory
Examples of initialized pointersint i = 1;char c = 'y';int *ptr = &i; // ptr is a pointer to int ichar *t = &c; // t is a pointer to a char c
Examples of uninitialized pointersint *iPtr; // iPtr is a pointer to an intchar *s ; // s is a pointer to a charRational *rPtr; // rPtr is a pointer to a // Rational
Syntax
TypeName * PointerName = &ObjectName
Indicates pointer object
Indicates to take the address of the object
Indirection Operator *An asterisk has two uses with regard to pointers In a definition, it indicates that the object is a
pointerchar *s; // s is of type pointer to char
In expressions, when applied to a pointer it evaluates to the object to which the pointer pointsint i = 1;
int *ptr = &i; // ptr points to i
*ptr = 2;
cout << i << endl; // display a 2
Address Operator &In a definition, & is used to define a reference to an objectIn expressions, when applied to a object as unary operator, & evaluates the address of the object
int i = 1;int j = 2;int *ptr;
ptr = &i; // ptr points to location of i*ptr = 3; // contents of i are updatedptr = &j; // ptr points to location of j*ptr = 4; // contents of j are updated
cout << i << " " << j << endl;
Memory Depiction
0xF001
0xF0020xF003
0xF004
0xF000
0xF005
0xF006
0xF008
0xF0090xF00A
0xF00B
0xF007
0xF00C
0xF00D
c
char c = 'y';
int *ptr = &i;
ptr
char *t = &c;
t
’y’
*ptr = 2;
*t = ’W’; ’W’ ptr = (int*)&c;
t = (char*)&i;
0xF004
0xF000
0xF000
0xF004
i
int i = 1;
12
Null Address0 is a pointer constant that represents the empty or null address Its value indicates that pointer is not pointing to
a valid object Cannot dereference a pointer whose value is null
int *ptr = 0;
cout << *ptr << endl; // invalid, ptr // does not point to // a valid int
Big advisePointers are error prone and should be carefully Pointers are error prone and should be carefully manipulated. We always prefer to use reference manipulated. We always prefer to use reference object instead of pointer object when ever object instead of pointer object when ever possiblepossiblePointer should be always initialized at definition. Pointer should be always initialized at definition. If there is not a object to point to, initialize it If there is not a object to point to, initialize it with null pointer (set its value to 0)with null pointer (set its value to 0)First check the validity of a pointer before using First check the validity of a pointer before using itit
if( ptr != 0 ) cout << *ptr << endl;
ConsiderRational r(4,3);
Rational *rPtr = &r;
To select a member of r using rPtr and member selection, operator precedence requires (*rPtr).Insert(cout);
This syntax is clumsy, so C++ provides the indirect member selector operator ->
rPtr->Insert(cout);
Member Indirection
Pointers as parametersvoid IndirectSwap(char *Ptr1, char *Ptr2) {
char c = *Ptr1;*Ptr1 = *Ptr2;*Ptr2 = c;
}
int main() {
char a = 'y';char b = 'n';IndirectSwap(&a, &b);cout << a << b << endl;return 0;
}
Pointers to pointersint i = 5;int *Ptr = &i;int **PtrPtr = 0;PtrPtr = &Ptr;
PtrPtr Ptr i
51001100210031004
1011101210131014
1101110211031104
cout << Ptr << endl;cout << PtrPtr << endl;
Cout << *Ptr << endl;cout << *PtrPtr << endl;cout << **PtrPtr << endl;
// 1001// 1011
// 5// 1001// 5
Constants and PointersA constant pointer is a pointer such that we cannot change the location to which the pointer pointschar c = 'c';const char d = 'd';char * const ptr1 = &c;ptr1 = &d; // illegal*ptr1 = ’e’; // legal
A pointer to a constant value is a pointer object such that the value at the location to which the pointer points is considered constantconst char *ptr2 = &d;*ptr2 = 'e'; // illegal: cannot change d // through indirection with ptr2Ptr2 = &c; // legal
Arrays and Pointers
In C++ the name of an array is consider to be a constant pointer and points to first element of the array
int A[5] = {10,20,30,40,50};
int B[10]={0};
Ptr11000100410081012101610201024102810321036104010441048105210561060
A[0]A[1]A[2]A[3]A[4]B[0]B[1]B[2]B[3]B[4]B[5]B[6]B[7]B[8]B[9]
Ptr2
Ptr3
Ptr4
10203040500000000000
int *Ptr1 = A; int *Ptr2 = B;int *Ptr3 = &B[0]; int *ptr4 = &B[5];
Arrays and PointersIncrement and decrement operator can be applied to any type of pointer object++Ptr1;cout<< ptr1 << endl; cout<< *ptr1 << endl;
--Ptr4;cout<< ptr4 << endl; cout<< *ptr4 << endl;
Ptr11000100410081012101610201024102810321036104010441048105210561060
A[0]A[1]A[2]A[3]A[4]B[0]B[1]B[2]B[3]B[4]B[5]B[6]B[7]B[8]B[9]
Ptr4
10203040500000000000100420103
60
Arrays and PointersPtr1
1000100410081012101610201024102810321036104010441048105210561060
A[0]A[1]A[2]A[3]A[4]B[0]B[1]B[2]B[3]B[4]B[5]B[6]B[7]B[8]B[9]
10203040500000000000
Ptr1 += 3;cout<< Ptr1 << endl; cout<< *Ptr1 << endl;
Ptr4 -= 4;cout<< Ptr4 << endl;
Ptr1 = Ptr4 + 3;cout<< Ptr4 << endl;
Ptr4 += 9;
int *Ptr = Ptr1 + Ptr2 // illegal
Offset operation for pointer object
Pointer object plus or minus a integer constant
Ptr4
//be dangerous!!!
Arrays and PointersPtr1
1000100410081012101610201024102810321036104010441048105210561060
A[0]A[1]A[2]A[3]A[4]B[0]B[1]B[2]B[3]B[4]B[5]B[6]B[7]B[8]B[9]
10203040500000000000
cout<< Ptr1 << endl;
cout<< Ptr1[0] << endl;
cout<< *Ptr1 << endl;
cout<< Ptr1[3] << endl;
cout<< *(Ptr1+3) << endl;
Subscribing a pointer object [ ] operator for pointer
Pointers to functionUsage: as function parameters
Some member functions of SimpleWindow
void SetTimerCallback(TimerTickCallbackFunction Callback);
The name of a function is just a pointer to the function
Definition of pointers to function
ReturnType ( *FuncPtrName ) ( ParameterList );
int (*TimerTickCallbackFunction)();int (*MouseClickCallback)(const Position &);
Dynamic objectswhose memory is acquired at run time
Local objects and parameters
Object memory is acquired automatically
Object memory is returned automatically when object goes out of scope
Dynamic objects
Object memory is acquired by program with an allocation request new operation
Dynamic objects can exist beyond the function in which they were allocated
Object memory is returned by a deallocation request delete operation
Deference with local object
Operation specifies The type and number of objects
If there is sufficient memory to satisfy the request A pointer to sufficient memory is returned by the
operation
If there is insufficient memory to satisfy the request An exception is generated
An exception is an error state/condition which if not handled (corrected) causes the program to terminate
General New Operation Behavior
Memory for dynamic objects Requested from the free store
Free store is memory controlled by operating system
The Basic New Form
Syntax
Beware The newly acquired memory is uninitialized
unless there is a default TypeName constructor
Ptr = new TypeName ;
Where Ptr is a pointer of type TypeName
Examples
int *iptr = new int;Rational *rptr = new Rational;
--iptr
0/1rptr
Rational object with default initialization
Uninitialized int object
Another Basic New Form
Initialization The newly acquired memory is initialized
using a TypeName constructor ParameterList provides the parameters to the
constructor
Syntax
TypeName *Ptr = new TypeName(ParameterList);
Where Ptr is a pointer of type TypeName
Examples
int *iPtr = new int(10);Rational *rPtr = new Rational(1,2);
rPtr
10iPtr
1/2
The Primary New Form
Syntax
Where Ptr is a pointer of type SomeType SizeExpression is the number of contiguous objects of
type TypeName to be constructed -- we are making a list
Note The newly acquired list is initialized if there is a default
TypeName constructor
Because of flexible pointer syntax Ptr can be considered to be an array
TypeName *Ptr = new TypeName[SizeExpression];
Examplesint *A = new int [3];Rational *R = new Rational[2];A[1] = 5;Rational r(2/3);R[0] = r;
—A
2/3R
5
0/1
—
Right Array For The Jobcout << "Enter list size: ";int n;cin >> n;int *A = new int[n];
GetList(A, n);SelectionSort(A, n);DisplayList(A, n);
Note:
Use of the container classes of the STL is preferred from a software engineering viewpoint. For example vector class
Delete OperatorsForms of request
// used if storage came from newdelete P;
// used if storage came from new[]delete [] P;
Storage pointed to by P is returned to free store, and any program can reuse it P is now undefined
Cleaning Up
int n;cout << "Enter list size: ";cin >> n;
int *A = new int[n];
GetList(A, n);SelectionSort(A, n);DisplayList(A, n);
delete [] A;
Dangling Pointer Pitfallint *A = new int[5];for (int i = 0; i < 5; ++i) A[i] = i;
int *B = A;A
B0 1 2 3 4
A
B
0?
Beware this memory do not belong to the program any more
delete [] A;A = 0;
if(B != 0) cout << B[0] << endl; //???
Memory Leak Pitfallint *A = new int [5];for (int i = 0; i < 5; ++i)
A[i] = i;
A 0 1 2 3 4
A 0 1 2 3 4
-- -- -- -- --
These memory cannot be accessed by any program
A = new int [5];
A Simple Dynamic List Type
A good example of the usage of dynamic objects
What we want
An integer list data type IntList with the basic features of the vector data type from the Standard Template Library
Features and abilities
True object Can be passed by value and reference Can be assigned and copied
Inspect and mutate individual elements Inspect list size Resize list Insert and extract a list
Sample IntList UsageIntList A( 5, 1);IntList B(10, 2);IntList C( 5, 4);
for (int i = 0, i < A.size(); ++i) {
A[i] = C[i];}
cout << A << endl; // [ 4 4 4 4 4 ]
A = B;A[1] = 5;cout << A << endl; // [ 2 5 2 2 2 2 2 2 2 2 ]
IntList Definitionclass IntList {public:
// constructors IntList(int n = 10, int val = 0); IntList(const int A[], int n); IntList(const IntList &A);
// destructor ~IntList();
// inspector for size of the list int size() const; // assignment operator IntList & operator=(const IntList &A);
IntList Definition (continued)public:
// inspector for element of constant listconst int& operator[](int i) const;// inspector/mutator for element of// nonconstant listint& operator[](int i);// resize listvoid resize(int n = 0, int val = 0);// convenience for adding new last elementvoid push_back(int val);
private:// data membersint *Values; // pointer to elementsint NumberValues; // size of list
};
IntList Definition (continued)
// IntList auxiliary operators -- nonmembers
ostream& operator<<(ostream &sout, const IntList &A);
istream& operator>>(istream &sin, IntList &A);
Default ConstructorIntList::IntList(int n, int val) { assert(n > 0);
NumberValues = n; Values = new int [n];
assert(Values);
for (int i = 0; i < n; ++i) {
Values[i] = val; }
}
Gang of Three RuleIf a class has a data member that points to dynamic memory then that class normally needs a class-defined Copy constructor
Constructor that builds an object out of an object of the same type
Member assignment operator Resets an object using another object of the
same type as a basis Destructor
Anti-constructor that typically uses delete the operator on the data members that point to dynamic memory
Why A Tailored Copy Constructor
Suppose we use the default copy constructorIntList A(3, 1);
IntList B(A);
B 3
1 1 1A 3
2And then A[2] = 2;
Then B[2] is changed! Not what a client would expect
Implication Must use tailored copy constructor
Why A Tailored Copy Constructor
An other case, suppose we use the default copy constructor
IntList A(3, 1); {
IntList B(A); B[1] = 5; ... }
A[2] = 2; //what happened ???
Implication Must use tailored copy constructor
B 3
1 1A 3
15? ? ?
Tailored Copy ConstructorIntList::IntList(const IntList &A) {
NumberValues = A.size();Values = new int [size()];assert(Values);
for (int i = 0; i < size(); ++i)Values[i] = A[i];
}What kind of subscripting is being performed? A 3
1 111
B 31 111
Gang Of ThreeWhat happens when an IntList goes out of scope?
If there is nothing planned, then we would have a memory leak
Need to have the dynamic memory automatically deleted
Define a destructor A class object going out of scope automatically
has its destructor invoked
IntList::~IntList() { delete [] Values;}
This PointerConsider
this
Inside a member function or member operator this is a pointer to the invoking object
IntList::size() { return NumberValues;}
or equivalently
IntList::size() { return this->NumberValues;}
First Assignment Attempt
Algorithm
Return existing dynamic memory to free store
Acquire sufficient new dynamic memory
Copy the size and the elements of the source object to the target element
Initial Implementation (Wrong)
IntList& operator=(const IntList &A) { NumberValues = A.size();
delete [] Values; Values = new int [NumberValues ]; assert(Values);
for (int i = 0; i < A.size(); ++i) Values[i] = A[i];
return A;}
Consider what happens with the code segmentIntList C(5,1);C = C;
Member Assignment OperatorIntList& IntList::operator=(const IntList &A) {
if (this != &A) {
delete [] Values;
NumberValues = A.size();Values = new int [A.size()];assert(Values);
for (int i = 0; i < A.size(); ++i) { Values[i] = A[i];}
}
return *this;}
Accessing List Elements
// Compute an rvalue (access constant element)const int& IntList::operator[](int i) const { assert((i >= 0) && (i < size())); return Values[i];
}
// Compute an lvalueint& IntList::operator[](int i) { assert((i >= 0) && (i < size())); return Values[i];
}
Stream OperatorsShould they be members?
class IntList {// ...ostream& operator<<(ostream &sout);// ...
};
Answer is based on the form we want the operation to take
IntList A(5,1);A << cout; // member form (unnatural)cout << A; // nonmember form (natural)
Beware of FriendsIf a class needs to
Can provide complete access rights to a nonmember function, operator, or even another class Called a friend
Declaration example
class IntList {friend ostream& operator<< (
ostream &sout, const IntList &A);friend istream& operator>> (
ostream &sin, const IntList &A);
// ...
};
Implementing Friend <<ostream& operator<<(ostream &sout, const IntList &A){ sout << "[ "; for (int i = 0; i < A.NumberValues; ++i)
{ sout << A.Values[i] << " ";
} sout << "]";
return sout;}
Why client can directly access the private data member of A ?
Is it a good program ???
Proper << Implementationostream& operator<<(ostream &sout, const IntList &A){ sout << "[ "; for (int i = 0; i < A.size(); ++i)
{ sout << A[i] << " ";
} sout << "]";
return sout;}
End of Chapter End of Chapter 1111
Exercises 11.47, 11.49 and 11.50 as in oneExercises 11.55
Home worksHome works