473,471 Members | 2,005 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

delete a composite

This question is a little embarrassing... I have a boolean expressions
interpreter with its composite (see Go4's "Design Patterns" book).
here is a simple leaf of the composite:

class Constant : public BooleanExp {
public:
Constant(bool);
virtual ~Constant();
virtual void Accept(BooleanExpVisitor&);

bool GetValue() const {return _value;}

private:
bool _value;
};

and here is a composite complying with the BooleanExp interface:

class AndExp : public BooleanExp {
public:
AndExp(BooleanExp*, BooleanExp*);
virtual ~AndExp();
virtual void Accept(BooleanExpVisitor&);

private:
BooleanExp* _operand1;
BooleanExp* _operand2;
};

Consider a few other classes that are similar in concept, including
OrExp, VariableExp and so on. The Context class maps variables to
their boolean values.
Now I want to evaluate an expression:

BooleanExp *expression;
Context cont;

context.Assign(x, false);
context.Assign(y, true);

EvaluationVisitor visitor(cont);

expression = new OrExp (
new AndExp (new Constant (true), x),
new AndExp (y, new NotExp (x))
);

bool result = expression->Accept(visitor);

Up to here everything is good. My question is, how do I collect the
garbage?
What I have at the moment is

delete expression;

Do you think this will do?
I have a virtual destructor for each of the BooleanExp (concrete)
subclasses, and they all do nothing. Correct me if I'm wrong, but I
don't think it's a good idea to let these destructors have the
responsibility to clean up since the dynamic allocations are performed
out of the class.

TIA,

Matan Nassau
Jul 22 '05 #1
4 1417

"Matan Nassau" <Fo************@ICQMail.com> wrote in message
news:3c**************************@posting.google.c om...
This question is a little embarrassing... I have a boolean expressions
interpreter with its composite (see Go4's "Design Patterns" book).
here is a simple leaf of the composite:

class Constant : public BooleanExp {
public:
Constant(bool);
virtual ~Constant();
virtual void Accept(BooleanExpVisitor&);

bool GetValue() const {return _value;}

private:
bool _value;
};

and here is a composite complying with the BooleanExp interface:

class AndExp : public BooleanExp {
public:
AndExp(BooleanExp*, BooleanExp*);
virtual ~AndExp();
virtual void Accept(BooleanExpVisitor&);

private:
BooleanExp* _operand1;
BooleanExp* _operand2;
};

Consider a few other classes that are similar in concept, including
OrExp, VariableExp and so on. The Context class maps variables to
their boolean values.
Now I want to evaluate an expression:

BooleanExp *expression;
Context cont;

context.Assign(x, false);
context.Assign(y, true);

EvaluationVisitor visitor(cont);

expression = new OrExp (
new AndExp (new Constant (true), x),
new AndExp (y, new NotExp (x))
);

bool result = expression->Accept(visitor);

Up to here everything is good. My question is, how do I collect the
garbage?
What I have at the moment is

delete expression;

Do you think this will do?
It won't free the allocated memory.
I have a virtual destructor for each of the BooleanExp (concrete)
subclasses, and they all do nothing. Correct me if I'm wrong, but I
don't think it's a good idea to let these destructors have the
responsibility to clean up since the dynamic allocations are performed
out of the class.


It's quite common for classes to 'take ownership' of pointers in this way.
It's the basis of most smart pointer classes for instance. I would do the
deletes in the destructors, anything else is going to be very tedious and
therefore very error prone.

john
Jul 22 '05 #2
Matan Nassau wrote:
This question is a little embarrassing... I have a boolean expressions
interpreter with its composite (see Go4's "Design Patterns" book).
here is a simple leaf of the composite:

class Constant : public BooleanExp {
public:
Constant(bool);
virtual ~Constant();
virtual void Accept(BooleanExpVisitor&);

bool GetValue() const {return _value;}

private:
bool _value;
};

and here is a composite complying with the BooleanExp interface:

class AndExp : public BooleanExp {
public:
AndExp(BooleanExp*, BooleanExp*);
virtual ~AndExp();
virtual void Accept(BooleanExpVisitor&);

private:
BooleanExp* _operand1;
BooleanExp* _operand2;
};

Consider a few other classes that are similar in concept, including
OrExp, VariableExp and so on. The Context class maps variables to
their boolean values.
Now I want to evaluate an expression:

BooleanExp *expression;
Context cont;

context.Assign(x, false);
context.Assign(y, true);

EvaluationVisitor visitor(cont);

expression = new OrExp (
new AndExp (new Constant (true), x),
new AndExp (y, new NotExp (x))
);

bool result = expression->Accept(visitor);

Up to here everything is good. My question is, how do I collect the
garbage?
It depends on who [you think] owns those pointers. The owner should
dispose of them. There is no "garbage collection", everybody disposes of
their own rubbish.
What I have at the moment is

delete expression;

Do you think this will do?
How should we know? You posted no implementation of your classes. Does
'AndExp' own the object, to which pointers 'operand_1' and 'operand_2'
point? If so, it should dispose of them in the destructor.
I have a virtual destructor for each of the BooleanExp (concrete)
subclasses, and they all do nothing. Correct me if I'm wrong, but I
don't think it's a good idea to let these destructors have the
responsibility to clean up since the dynamic allocations are performed
out of the class.


Dynamic allocations for std::auto_ptr are performed "out of the class" but
it doesn't prevent std::auto_ptr from being responsible of disposing the
object. It all depends on what responsibilities you assign to your classes.

Don't forget to document them.

Victor
Jul 22 '05 #3
WT
Thank you very much, Victor, and you, John, for your fast replies.
delete expression;

Do you think this will do?
How should we know? You posted no implementation of your classes. Does
'AndExp' own the object, to which pointers 'operand_1' and 'operand_2'
point? If so, it should dispose of them in the destructor.


I posted the implementations that I thought were important for the question,
and I ommited others.
OrExp is realy similar to AndExp. I could actually say that the two are
identical, and the only difference in behavior is actually in the visitor,
which ORs the two operands instead of ANDs them when OrExp accepts the
visit.
Here is the Accept operation of OrExp:

void OrExp::Accept(BooleanExpVisitor &visitor)
{
_operand1->Accept(visitor);
_operand2->Accept(visitor);
visitor.VisitOrExp(this);
}

The visitor class should be provided as well, I apologize.

class EvaluationVisitor : public BooleanExpVisitor {
public:
EvaluationVisitor(Context&);
~EvaluationVisitor();
bool PopResult();
virtual void VisitVariableExp(VariableExp*);
virtual void VisitConstant(Constant*);
virtual void VisitAndExp(AndExp*);
virtual void VisitOrExp(OrExp*);
virtual void VisitNotExp(NotExp*);
private:
Context& _context;
deque <bool> _result;
};

The class complies with the BooleanExpVisitor interface. it overrides its
defaults. PopResult pops the last result out of the _result stack.
Here's VisitOrExp:

void EvaluationVisitor::VisitOrExp(OrExp *exp)
{
if (_result.empty())
throw false;
// pop, pop, evaluate and push
bool val2 = _result.back();
_result.pop_back();
bool val1 = _result.back();
_result.pop_back();
_result.push_back( val1 || val2 );
}

VisitVariableExp will find the value of the variable in the context map,
which is a member of the visitor, and will push it into the stack.
VisitConstant will get the constant value and push it into the stack.
NotExp is the same class as OrExp and AndExp with one operand instead of 2,
and another difference in the visitor which NOTs the operand of the NotExp
object.
Constant is a leaf similar to VariableExp, with the 2 differences similiar
to those above: a bool member variable which holds its value, instead of a
char* which holds the variable's name.
Context maps variable names to their boolean values, and it is useful to
change the result of an expression without changing the expression. It has
the following interface:

class Context {
public:
bool Lookup(const char*) const;
void Assign(VariableExp*, bool);
private:
map<const char*, bool> _theMap;
};

I think the interface speaks for itself. It's pretty much a wrapper for the
map, only providing just the necessary manipulation methods.
Dynamic allocations for std::auto_ptr are performed "out of the class" but
it doesn't prevent std::auto_ptr from being responsible of disposing the
object.
That's also what John said. But I think this is because that is exactly the
idea behind smart pointers: take over the responsibility of cleaning up, and
do it safely. What I was hesitating about, was what you mentioned next:
It all depends on what responsibilities you assign to your classes.
my classes don't have to help the client with anything other than
interpreting boolean expressions. if they make a mess, ofcourse they must
clean after. However, at the moment it's the client which allocates the
objects that construct the composite. I could go John's way, and delete
everything in the the constructors, at the price of safety (any other price
I'm unaware of?). Or I could go with the more "apathetic" attitude, allowing
the client to allocate objects - but not cleaning up after it. I think it
realy is a matter of opinion, and there is no strict answer to that...
Don't forget to document them.


Good practice is what I'm practicing. Documentation is a good practice
indeed.

Matan
Jul 22 '05 #4
Thank you very much, Victor, and you, John, for your fast replies.
delete expression;

Do you think this will do?
How should we know? You posted no implementation of your classes. Does
'AndExp' own the object, to which pointers 'operand_1' and 'operand_2'
point? If so, it should dispose of them in the destructor.


I posted the implementations that I thought were important for the question,
and I ommited others.
OrExp is realy similar to AndExp. I could actually say that the two are
identical, and the only difference in behavior is actually in the visitor,
which ORs the two operands instead of ANDs them when OrExp accepts the
visit.
Here is the Accept operation of OrExp:

void OrExp::Accept(BooleanExpVisitor &visitor)
{
_operand1->Accept(visitor);
_operand2->Accept(visitor);
visitor.VisitOrExp(this);
}

The visitor class should be provided as well, I apologize.

class EvaluationVisitor : public BooleanExpVisitor {
public:
EvaluationVisitor(Context&);
~EvaluationVisitor();
bool PopResult();
virtual void VisitVariableExp(VariableExp*);
virtual void VisitConstant(Constant*);
virtual void VisitAndExp(AndExp*);
virtual void VisitOrExp(OrExp*);
virtual void VisitNotExp(NotExp*);
private:
Context& _context;
deque <bool> _result;
};

The class complies with the BooleanExpVisitor interface. it overrides its
defaults. PopResult pops the last result out of the _result stack.
Here's VisitOrExp:

void EvaluationVisitor::VisitOrExp(OrExp *exp)
{
if (_result.empty())
throw false;
// pop, pop, evaluate and push
bool val2 = _result.back();
_result.pop_back();
bool val1 = _result.back();
_result.pop_back();
_result.push_back( val1 || val2 );
}

VisitVariableExp will find the value of the variable in the context map,
which is a member of the visitor, and will push it into the stack.
VisitConstant will get the constant value and push it into the stack.
NotExp is the same class as OrExp and AndExp with one operand instead of 2,
and another difference in the visitor which NOTs the operand of the NotExp
object.
Constant is a leaf similar to VariableExp, with the 2 differences similiar
to those above: a bool member variable which holds its value, instead of a
char* which holds the variable's name.
Context maps variable names to their boolean values, and it is useful to
change the result of an expression without changing the expression. It has
the following interface:

class Context {
public:
bool Lookup(const char*) const;
void Assign(VariableExp*, bool);
private:
map<const char*, bool> _theMap;
};

I think the interface speaks for itself. It's pretty much a wrapper for the
map, only providing just the necessary manipulation methods.
Dynamic allocations for std::auto_ptr are performed "out of the class" but
it doesn't prevent std::auto_ptr from being responsible of disposing the
object.
That's also what John said. But I think this is because that is exactly the
idea behind smart pointers: take over the responsibility of cleaning up, and
do it safely. What I was hesitating about, was what you mentioned next:
It all depends on what responsibilities you assign to your classes.
my classes don't have to help the client with anything other than
interpreting boolean expressions. if they make a mess, ofcourse they must
clean after. However, at the moment it's the client which allocates the
objects that construct the composite. I could go John's way, and delete
everything in the the constructors, at the price of safety (any other price
I'm unaware of?). Or I could go with the more "apathetic" attitude, allowing
the client to allocate objects - but not cleaning up after it. I think it
realy is a matter of opinion, and there is no strict answer to that...
Don't forget to document them.


Good practice is what I'm practicing. Documentation is a good practice
indeed.

Matan
Jul 22 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Patrizio | last post by:
Hi All, I've the following table with a PK defined on an IDENTITY column (INSERT_SEQ): CREATE TABLE MYDATA ( MID NUMERIC(19,0) NOT NULL, MYVALUE FLOAT NOT NULL, TIMEKEY ...
3
by: Alexander Anderson | last post by:
I have a DELETE statement that deletes duplicate data from a table. It takes a long time to execute, so I thought I'd seek advice here. The structure of the table is little funny. The following is...
6
by: Matan Nassau | last post by:
Hello. i have a composite which i want to delete. this is a composite which represents a boolean expression (see a previous post of mine with more details at...
0
by: AshifToday | last post by:
this was my and my frineds little project in earlier classes, the program seperates the composite and prime numbers in two sections of the screen ===================== /* This program has...
2
by: ms | last post by:
Access 2000: I am trying to delete duplicate records imported to a staging table leaving one of the duplicates to be imported into the live table. A unique record is based on a composite key of 3...
18
by: Thomas A. Anderson | last post by:
I am a bit confused in creating a composite primary key. I have three table with two of the tables containing primary keys. I have two of the tables (each with a primary key) having one to many...
4
by: Ismail Rajput | last post by:
Is there any option we can use Composite DataKeyField in the DataList and DataGrid?
14
by: dave.dolan | last post by:
Basically I'd like to implement the composite design pattern with leaves that are either of reference or value types, but even using generics I can't seem to avoid boxing (using ArrayList or...
2
by: lfhenry | last post by:
Hi All, I am about to make some changes to a process we have. The new process will have a new table who's job it is to store temporarily data such as customer, clerkno,productno, storeno , amount,...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.