Exercises: Memory Management in C++, Boost Smart Pointers **SAMPLE ...

harpywarrenΛογισμικό & κατασκευή λογ/κού

14 Δεκ 2013 (πριν από 3 χρόνια και 6 μήνες)

67 εμφανίσεις

Exercises: Memory Management in C++, Boost Smart Pointers

**SAMPLE**

Part I: Advanced Raw Pointers

(1.

The different Kinds of Memory)

There are three main kinds of memory that C++ supports, namely
stack,

heap

and
static

memory.

Answer the following questions:

a)

Describe what the intent of each memory type is and why it is needed in general.

b)

Describe the lifecycle of
stack,

heap

and
static

objects. In particular, create a test program to
show how to realise this lifecycle in C++.

c)


Compare stack and heap objects wi
th regard to run
-
time efficiency and memory allocation.

d)

Why are heap objects used when we wish to implement polymorphic behavior in classes?

e)

Can you give general guidelines on which kind of memory to use in which kind of applications
(hint: performance, re
liability etc.)

f)


(2.

Some ‘bad’ Memory Scenarios
, initial ‘nitty
-
gritty’ Problems
)

This exercise can be seen as a review of precise knowledge of raw pointers in C++ before we make the
transition to boost smart pointers.

Some of the problems have names such as
dangling pointers
,
double
free bugs

and memory leaks, just to name a few.

The objective of this exercise is to analyse the following code and determine what is happening (not all
code compiles and you need to discove
r why not):


// 1.


int
* p;


//cout <<
*p << endl;



// 2.


p = 0;


//cout << *p << endl;



// 3.


p =
new

int
;


*p = 1;


cout << *p << endl;



// 4.


int
* p2 = p;


cout << *p2 << endl;



*p = 20;


cout << *p2 << endl;




// 5.


p = 0;


cout << *p2 << endl;


//cout << *p << endl;



// 6.


del
ete

p;


cout <<
"step 6 "

<< *p2 << endl;


//cout << *p << endl;



// 7.


delete

p;
delete

p;



// 8.



{
// Define a new scope




double
* d =
new

double
;



*d = 1.0;



}


Discuss each of the scenarios 1, .., 8 in detail. The objective is that you know exa
ctly what this code
means and what the consequences of use are.


(3.

Double Pointers and Matrix (two
-
Dimensional Data Structures)

)

This a good exercise to test your knowledge of pointers because we will be using ‘double pointers’. In
most applications we do n
ot use this technique because of the availability of data structures in STL and
boost that hide this level of detail. The objective is to create a matrix consisting of complex numbers.
The
re are several options at different levels of flexibility:



const l
ong NR = 20; const long NC = 30;



Complex matrix[NR][NC];



Complex** matrix2;



Complex* matrix3[NR];


Create instances of each of these data structures by allowing memory in the appropriate manner. Make
sure that you do not get memory leaks or dangling
pointers.


Part II: The Boost Smart Pointers


(4.

STL
auto_ptr

versus Boost
scoped_ptr
)

These two template classes serve the same purpose, namely:



Acquire some resources



Perform some operations



Free the acquired resources

The advantage in both cases is

that allocated memory is freed automatically.
But
scoped_ptr

is more
robust because there is no transfer of ownership
nor

is
shared ownership of the
allocated resource
allowed (if you try you will get a compiler error).

Answer the following questions:

a)

Tes
t these classes by creating a dynamically allocated object in a given scope

b)

Try assigning scoped and auto pointers? What happens in each case and what are the
consequences in each case?

c)

Can
auto_ptr

and
scoped_ptr

hold a pointer to a dynamically associated

array?
Consider
using STL
vector<T>

in combination with these as an alternative.

d)

Create a solution for part c) based on the boost
scoped_array

template class.

e)

Consider using
scoped_ptr<vector<T> >

as a solution.

The input to this set of questions is the f
ollowing classic C++ code which you need to implement using
the new template classes.

The input is the following code:

int

main()

{


{



// Single object



double
* d1 =
new

double
(1.0);



double
* dsecond = d1;




// Array



long

N = 100;



double
* darr =
n
ew

double
[N];
// Notice the square brackets




for

(
long

j = 0; j < N; ++j)



{




darr[j] = 2.3;



}




delete

d1;



delete

[] darr;


}



return

0;

}




(5.

Shared Pointers, what is the Reference Count?
)

We consider two classes that share a common data member

(at object level). We use a shared pointer in
this class so that it is not destroyed when an object goes out scope:

class

C1

{

private
:



//double* d; OLD WAY



boost::shared_ptr<
double
> d;

public
:


C1(boost::shared_ptr<
double
> value) : d(value) {}


vir
tual

~C1() { cout <<
"
\
nC1 destructor
\
n"
;}


void

print()
const

{ cout <<
"Value "

<< *d; }

};


class

C2

{

private
:



//double* d; // OLD WAY



boost::shared_ptr<
double
> d;

public
:


C2(boost::shared_ptr<
double
> value) : d(value) {}


virtual

~C2() { cout <<

"
\
nC2 destructor
\
n"
; }


void

print()
const

{ cout <<
"Value "

<< *d; }

};


Now consider the following code:



{




cout <<
"Built
-
in types
\
n"
;




boost::shared_ptr<
double
> commonValue(
new

double

(3.1415));




cout << commonValue.use_count() << endl;





{





C1 object1(commonValue);





C2 object2(commonValue);




}



}


Answer the following questions:


a)

Describe in your own words what the reference count is on
commonValue

b)

Use the member function
use_count()
to verify your intuition


(6.

Shared Pointers and
Use
r
-
defined Types
)

Consider the
following two
classes containing a common instance of a user
-
defined type (in this case a
Cartesian
Point

class):


class

D1

{

private
:





boost::shared_ptr<Point> p;

public
:


D1(boost::shared_ptr<Point> value) : p(value) {}


virtual

~D1() { cout <<
"
\
nD1 destructor
\
n"
;}


void

print()
const

{ cout <<
"
\
nValue "

<< *p; }

};


class

D2

{

private
:





boost::shared_ptr<Point> p;

public
:


D2(boost::shared_ptr<Point> value) : p(value) {}


virtual

~D2() { cout <<
"
\
nD2 destructor
\
n"
;}


void

print()
const

{ cout <<
"
\
nValue "

<< *p; }

};

Now consider the following code:



// Now with user
-
defined types, Create dynamic memory



boost::shared_ptr <Point> myPoint (
new

Point(1.0, 23.3));



cout <<
"Reference count: "

<< myPoint.use_count(
) << endl;



{




D1 point1(myPoint);




cout <<
"Reference count: "

<< myPoint.use_count() << endl;




D1 point2(myPoint);




cout <<
"Reference count: "

<< myPoint.use_count() << endl;




//point1.print();




}



cout <<
"Reference count: "

<< myPoint.us
e_count() << endl;



{




D2 object3(myPoint);




//object3.print();




cout <<
"Reference count: "

<< myPoint.use_count() << endl;



}






cout <<
"Reference count: "

<< myPoint.use_count() << endl;


Answer the following questions:

a)

What is the reference
count on the shared resource
myPoint

at each line of the code?

b)

Use the
reset()

member function to
stop sharing ownership of the shared pointer. What do
you see?


Part III: Applying Boost Smart Pointers

(7.

Smart Pointers and STL Containers

)

One of the problem
s when using raw pointers in STL containers is that when they go out of scope the
container will contain null pointers. We also do not wish to
store by value in the containers because this
will cause a performance penalty for types where the copy operation

is expensive. A solution in this case
is to use shared pointers
. To this end, consider the simple class hierarchy:


class

Base

{
// Class with non
-
virtual destructor

private
:



public
:


Base() { }


virtual

~Base() { cout <<
"Base destructor
\
n
\
n"
; }


virtu
al

void

print()
const

= 0;

};


class

Derived :
public

Base

{
// Derived class

private
:




public
:


Derived() : Base() { }


~Derived() { cout <<
"Derived destructor
\
n"
; }


void

print()
const

{ cout <<
"derived object
\
n"
;}

};


Answer the following questions:


a)

Create a vector of shared pointers:


// Use in STL containers

typedef

std::vector<boost::shared_ptr<Base> > ContainerType;

typedef

ContainerType::iterator iterator;




b) Populate the container with instances of the derived classes and print the values i
n the

container.


c) Let some of the instances go out of scope. Determine what the happens to the elements of he

container.


(8.

Weak pointers)

Expain what is happening in the following code:


int

main()

{



boost::weak_ptr<
double
> w;


if

(w.expired())


{



cout <<
"No associated resource "

<< endl;


}


else


{



cout <<
"Has associated resource "

<< endl;


}






boost::shared_ptr<
double
> commonValue(
new

double

(3.1415));


cout <<
"Ref count: "

<< commonValue.use_count() << endl;
//1




w = commonValue;


co
ut <<
"Reference count:
"

<< commonValue.use_count() << endl;
//1


if

(w.expired())


{



cout <<
"No associated resource "

<< endl;


}


else


{



cout <<
"Has associated resource "

<< endl;


}



boost::shared_ptr<
double
> commonValue2(w);


cout <<
"Ref count
: "

<< commonValue.use_count() << endl;
//2






boost::shared_ptr<
double
> commonValue3 = w.lock();


cout <<
"Ref count: "

<< commonValue.use_count() << endl;
//3



return

0;}

© Datasim Education BV 2009