synthetic ood concepts and reuse lecture 4: separation of concerns
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 PresentationTRANSCRIPT
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