synthetic ood concepts and reuse lecture 4: separation of concerns

27
CSE 335: Software Design K. Stirewalt Synthetic OOD concepts and reuse Lecture 4: Separation of concerns Topics: – Complex concern: Memory management – Example: Complex operations on composite structures – Problem: Memory leaks – Solution: Reference counting

Upload: kiona-cantrell

Post on 02-Jan-2016

17 views

Category:

Documents


0 download

DESCRIPTION

Synthetic OOD concepts and reuse Lecture 4: Separation of concerns. Topics: Complex concern: Memory management Example: Complex operations on composite structures Problem: Memory leaks Solution: Reference counting. Motivation. Suppose we define a function: Expr* mkExpr(void) { - PowerPoint PPT Presentation

TRANSCRIPT

CSE 335: Software Design K. Stirewalt

Synthetic OOD concepts and reuseLecture 4: Separation of concerns

Topics:– Complex concern: Memory management– Example: Complex operations on composite structures– Problem: Memory leaks– Solution: Reference counting

CSE 335: Software Design K. Stirewalt

Motivation

Suppose we define a function:Expr* mkExpr(void)

{

Expr* l1 = new Literal(2);

Expr* v = new Variable(“x”);

Expr* t1 = new Add(l1,v);

Expr* l2 = new Literal(2);

Expr* t2 = new Multiply(l2,t1);

}

CSE 335: Software Design K. Stirewalt

Problem

Suppose a client program executes the code:...

Expr* e = mkExpr();

e->print(cout);

delete e;

...

What happens?

How could we ensure that when a composite object is deleted, its parts are also deleted?

CSE 335: Software Design K. Stirewalt

Solution

class Expr {

...

virtual ~Expr() {}

};

class BinaryExpr : public Expr {

...

~BinaryExpr()

{ delete(leftOperand); delete(rightOperand); }

...

};

CSE 335: Software Design K. Stirewalt

Or is it?

Often desirable for two or more composite objects to share the same component

Example:Expr* l = new Literal(2);Expr* v = new Variable(“x”);Expr* t1 = new Add(l,v);Expr* t2 = new Multiply(l,t1);

Here, object l is the child of two composite objects, t1 and t2.

Will our memory-reclamation scheme work now?

CSE 335: Software Design K. Stirewalt

Deleting composites that share parts

Not safe for destructor of a composite class to delete its children if these objects might be children of multiple composite objects

Solution: design a protocol that tracks references to objects and that deletes an object only when its reference count reaches 0.– Clients never call delete– Objects call delete on themselves!– Clients must explicitly notify objects when references

to these objects are assigned or overwritten

CSE 335: Software Design K. Stirewalt

Abstract ref-counting classclass RCObject { public: void addRef() { ++refCount; } void removeRef() { if(--refCount <= 0) delete this; }

protected: RCObject() : refCount(0) {} virtual ~RCObject() {}

private: int refCount;};

CSE 335: Software Design K. Stirewalt

Example

Modify class Expr as follows:

class Expr : public RCObject {

...

};

Subsequently, every class that derives from Expr will inherit reference counting infra-structure

CSE 335: Software Design K. Stirewalt

Example

Modify BinaryExpr as follows:

class BinaryExpr : public Expr {

...

BinaryExpr( Expr* l, Expr* r )

: leftOperand(l), rightOperand(r)

{ l->addRef(); r->addRef(); }

...

~BinaryExpr()

{ l->removeRef(); r->removeRef(); }

};

CSE 335: Software Design K. Stirewalt

Example (continued)

Now we write a function that creates an expression:

Expr* createExpression(void){ Expr* l = new Literal(2); Expr* v = new Variable(“x”); Expr* t1 = new Add(l,v); Expr* t2 = new Multiply(l,t1); return t2;}

Requires client to increment refCount of root object (pointed to here by t2 before it goes out of scope)

CSE 335: Software Design K. Stirewalt

Step 1

Expr* createExpression(void){ Expr* l = new Literal(2); Expr* v = new Variable(“x”); Expr* t1 = new Add(l,v); Expr* t2 = new Multiply(l,t1); return t2;}

l : LiteralrefCount=0

CSE 335: Software Design K. Stirewalt

Step 2

Expr* createExpression(void){ Expr* l = new Literal(2); Expr* v = new Variable(“x”); Expr* t1 = new Add(l,v); Expr* t2 = new Multiply(l,t1); return t2;}

l : LiteralrefCount=0

v : VariablerefCount=0

CSE 335: Software Design K. Stirewalt

Step 3

Expr* createExpression(void){ Expr* l = new Literal(2); Expr* v = new Variable(“x”); Expr* t1 = new Add(l,v); Expr* t2 = new Multiply(l,t1); return t2;}

l : LiteralrefCount=1

v : VariablerefCount=1

t1 : AddrefCount=0

CSE 335: Software Design K. Stirewalt

Step 4

Expr* createExpression(void){ Expr* l = new Literal(2); Expr* v = new Variable(“x”); Expr* t1 = new Add(l,v); Expr* t2 = new Multiply(l,t1); return t2;}

l : LiteralrefCount=2

v : VariablerefCount=1

t1 : AddrefCount=1

t2 : MultiplyrefCount=0

CSE 335: Software Design K. Stirewalt

Example (continued)

Client code then uses as follows:

...

Expr* e = createExpression();

e->addRef(); // new line

e->print(cout);

e->removeRef(); // rather than delete(e)

...

CSE 335: Software Design K. Stirewalt

Adding reference to returned object

e->addRef();e->print(cout);e->removeRef();

l : LiteralrefCount=2

v : VariablerefCount=1

t1 : AddrefCount=1

t2 : MultiplyrefCount=1

e

CSE 335: Software Design K. Stirewalt

Printing expression...

e->addRef();e->print(cout);e->removeRef();

l : LiteralrefCount=2

v : VariablerefCount=1

t1 : AddrefCount=1

t2 : MultiplyrefCount=1

e

CSE 335: Software Design K. Stirewalt

Removing ref: Step 1

e->addRef();e->print(cout);e->removeRef();

l : LiteralrefCount=1

v : VariablerefCount=1

t1 : AddrefCount=1

t2 : MultiplyrefCount=0

e

CSE 335: Software Design K. Stirewalt

Removing ref: Step 2

e->addRef();e->print(cout);e->removeRef();

l : LiteralrefCount=1

v : VariablerefCount=1

t1 : AddrefCount=0

t2 : MultiplyrefCount=0

e

CSE 335: Software Design K. Stirewalt

Removing ref: Step 3

e->addRef();e->print(cout);e->removeRef();

l : LiteralrefCount=0

v : VariablerefCount=1

t1 : AddrefCount=0

t2 : MultiplyrefCount=0

e

CSE 335: Software Design K. Stirewalt

Removing ref: Step 4

e->addRef();e->print(cout);e->removeRef();

l : LiteralrefCount=0

v : VariablerefCount=1

t1 : AddrefCount=0

t2 : MultiplyrefCount=0

e

CSE 335: Software Design K. Stirewalt

Removing ref: Step 5

e->addRef();e->print(cout);e->removeRef();

v : VariablerefCount=0

t1 : AddrefCount=0

t2 : MultiplyrefCount=0

e

CSE 335: Software Design K. Stirewalt

Removing ref: Step 6

e->addRef();e->print(cout);e->removeRef();

v : VariablerefCount=0

t1 : AddrefCount=0

t2 : MultiplyrefCount=0

e

CSE 335: Software Design K. Stirewalt

Removing ref: Step 7

e->addRef();e->print(cout);e->removeRef();

t1 : AddrefCount=0

t2 : MultiplyrefCount=0

e

CSE 335: Software Design K. Stirewalt

Removing ref: Step 8

e->addRef();e->print(cout);e->removeRef(); t2 : Multiply

refCount=0

e

CSE 335: Software Design K. Stirewalt

Conceptual (but flawed) alternative implementation of createExpression()

Expr* createExpression(void){

Expr* l = new Literal(2); l->addRef(); Expr* v = new Variable(“x”); v->addRef(); Expr* t1 = new Add(l,v); t1->addRef(); Expr* t2 = new Multiply(l,t1); t2->addRef(); l->removeRef(); v->removeRef(); t1->removeRef(); t2->removeRef(); // What happens here??? return t2;}

CSE 335: Software Design K. Stirewalt

“Mixin” classes

RCObject is an example of a “mixin” class– So-called because designed to encapsulate

orthogonal functionality that may be “mixed into” classes in an existing hierarchy

– Mixin classes are always abstract– May use multiple inheritance to incorporate

functionality in a mixin class if base class does not need it or if base class needs functionality from multiple mixin classes