472,807 Members | 1,740 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,807 software developers and data experts.

deleting a composite, double-delete problem

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 http://groups.google.ca/groups?hl=en...%26scoring%3Dd
)

VariableExp *x = new VariableExp("X");
VariableExp *y = new VariableExp("Y");
BooleanExp expression(
new OrExp(
new AndExp(new Constant(true), x),
new AndExp(x, y) ) );

represents the expression
(TRUE AND X) OR (X AND Y)

i have defined destructors for these dervied expressions as follows:

AndExp::~AndExp()
{
if (_operand1) {
delete _operand1;
_operand1 = 0;
}
if (_operand2) {
delete _operand2;
_operand2 = 0;
}
}

OrExp::~OrExp()
{
if (_operand1) {
delete _operand1;
_operand1 = 0;
}
if (_operand2) {
delete _operand2;
_operand2 = 0;
}
}
NotExp::~NotExp()
{
if (_operand) {
delete _operand;
_operand = 0;
}
}

for deleting the expression this way
delete expression;

i know this doesn't do the job, as the second AndExp in my example
here doesn't know that the first AndExp already deleted the
VariableExp x, and it tries to delete it - causing an error for
double-deleting.
my question is, how do I avoid it? what technique should i use to
delete the composite properly?

TIA,

Matan Nassau
Jul 22 '05 #1
6 2374
Matan Nassau wrote:
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 http://groups.google.ca/groups?hl=en...%26scoring%3Dd
)

VariableExp *x = new VariableExp("X");
VariableExp *y = new VariableExp("Y");
BooleanExp expression(
new OrExp(
new AndExp(new Constant(true), x),
new AndExp(x, y) ) );

represents the expression
(TRUE AND X) OR (X AND Y)

i have defined destructors for these dervied expressions as follows:

AndExp::~AndExp()
{
if (_operand1) {
delete _operand1;
_operand1 = 0;
}
if (_operand2) {
delete _operand2;
_operand2 = 0;
}
There is no need for those tests. 'delete 0' is a NOP. Just write

delete _operand1;
delete _operand2;

And setting them to 0 is also not needed -- the object is going away,
the values of its members are not accessible after the destructor is
done.
}

OrExp::~OrExp()
{
if (_operand1) {
delete _operand1;
_operand1 = 0;
}
if (_operand2) {
delete _operand2;
_operand2 = 0;
}
Same note as above.
}
NotExp::~NotExp()
{
if (_operand) {
delete _operand;
_operand = 0;
}
Same note.
}

for deleting the expression this way
delete expression;

i know this doesn't do the job, as the second AndExp in my example
here doesn't know that the first AndExp already deleted the
VariableExp x, and it tries to delete it - causing an error for
double-deleting.
my question is, how do I avoid it? what technique should i use to
delete the composite properly?


You've run into the classical problem of a shared pointer. The only
recommendation I have for shared pointers is: do _not_ use them.

The main question you need answered is: who _OWNS_ those objects.
Only the owner should be allowed to dispose of them (if they were
allocated dynamically). It often is considered OK if the object owns
itself. In order to respond properly to others' desire to dispose of
it it, the object has to count its uses (references). Take a look at
any existing reference counting schemes and use the simplest one. Or
use the most robust. In any case, it comes to the object deleting
itself when all references are released (reference counter comes to 0).

Victor
Jul 22 '05 #2

"Matan Nassau" <Fo************@ICQMail.com> wrote in message
news:3c**************************@posting.google.c om...
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 http://groups.google.ca/groups?hl=en...%26scoring%3Dd )

VariableExp *x = new VariableExp("X");
VariableExp *y = new VariableExp("Y");
BooleanExp expression(
new OrExp(
new AndExp(new Constant(true), x),
new AndExp(x, y) ) );

represents the expression
(TRUE AND X) OR (X AND Y)

i have defined destructors for these dervied expressions as follows:

AndExp::~AndExp()
{
if (_operand1) {
delete _operand1;
_operand1 = 0;
}
if (_operand2) {
delete _operand2;
_operand2 = 0;
}
}

OrExp::~OrExp()
{
if (_operand1) {
delete _operand1;
_operand1 = 0;
}
if (_operand2) {
delete _operand2;
_operand2 = 0;
}
}
NotExp::~NotExp()
{
if (_operand) {
delete _operand;
_operand = 0;
}
}

for deleting the expression this way
delete expression;

i know this doesn't do the job, as the second AndExp in my example
here doesn't know that the first AndExp already deleted the
VariableExp x, and it tries to delete it - causing an error for
double-deleting.
my question is, how do I avoid it? what technique should i use to
delete the composite properly?


This is a situation tailor made for a reference counted smart pointer. See
shared_ptr at http://www.boost.org/libs/smart_ptr/smart_ptr.htm for
instance.

Each smart pointer hold a reference count of how many other object are
referring to it, and only deletes itself when that count reaches zero.
Essentially you hand repsonsibility for the delete over to the smart pointer
class which only deletes when nothing can access the object any more.

The only change you are likely to have to make would be to replace raw
pointers with smart ones and remove the deletes from your code.

class AndExp
{
public:
~AndExp()
{
delete _operand1;
delete _operand2;
}
private:
BooleanExp* _operand1;
BooleanExp* _operand2;
};

becomes

class AndExp
{
public:
// no destructor
private:
boost::shared_ptr<BooleanExp> _operand1;
boost::shared_ptr<BooleanExp> _operand2;
};

john
Jul 22 '05 #3
Matan Nassau wrote:
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 http://groups.google.ca/groups?hl=en...%26scoring%3Dd
)

VariableExp *x = new VariableExp("X");
VariableExp *y = new VariableExp("Y");
BooleanExp expression(
new OrExp(
new AndExp(new Constant(true), x),
new AndExp(x, y) ) );

represents the expression
(TRUE AND X) OR (X AND Y)

i have defined destructors for these dervied expressions as follows:

AndExp::~AndExp()
{
if (_operand1) {
delete _operand1;
_operand1 = 0;
}
if (_operand2) {
delete _operand2;
_operand2 = 0;
}
}

OrExp::~OrExp()
{
if (_operand1) {
delete _operand1;
_operand1 = 0;
}
if (_operand2) {
delete _operand2;
_operand2 = 0;
}
}
NotExp::~NotExp()
{
if (_operand) {
delete _operand;
_operand = 0;
}
}

for deleting the expression this way
delete expression;

i know this doesn't do the job, as the second AndExp in my example
here doesn't know that the first AndExp already deleted the
VariableExp x, and it tries to delete it - causing an error for
double-deleting.
You have given ownership of the VariableExp object to two different
objects. (We say an object x 'owns' a dynamically-allocated object
y if x destroys y in its destructor.)

Two solutions spring to mind:

(i) avoid the situation of shared ownership by passing pointers to
distinct objects to the constructors.

(ii) deal with shared ownership using boost::shared_pointer. You should
be able to work out the details. See the Boost website for documentation.
my question is, how do I avoid it? what technique should i use to
delete the composite properly?


--
Regards,
Buster.
Jul 22 '05 #4
"John Harrison" <jo*************@hotmail.com> wrote in message news:<2h************@uni-berlin.de>...

This is a situation tailor made for a reference counted smart pointer. See
shared_ptr at http://www.boost.org/libs/smart_ptr/smart_ptr.htm for
instance.


Actually I already took a look at it before, and hesitated about it,
because I wasn't sure this is a problem a shared_ptr is designed to
solve. you cleared my doubts.

now everything is done, and life is good again.
...Well, almost. Because i don't understand how come it works. :)
you see, in addition to my existing constructor,

AndExp::AndExp(BooleanExp *op1, BooleanExp *op2)
{
_operand1.reset(op1);
_operand2.reset(op2);
}

I have a constructor which accepts a shared_ptr:

typedef boost::shared_ptr<BooleanExpPtr> BooleanExpPtr;

AndExp::AndExp(BooleanExpPtr op1, BooleanExpPtr op2)
{
_operand1 = op1;
_operand2 = op2;
}

(see previous post for details regarding my definitions).
and I call it with

typedef boost::shared_ptr<VariableExp> VariableExpPtr;

VariableExpPtr x(new VariableExp("X"));
VariableExpPtr y(new VariableExp("Y"));
BooleanExpPtr expression(new AndExp(x, y));

and it works. it compiles nicely with no complaints.
how come? just let me understand the concept of the shared_ptr:
VariableExp derives from BooleanExp so VariableExp is a BooleanExp.
Good. But VariableExpPtr does /not/ derive from BooleanExpPtr as much
as I understand the shared_ptr; it is merely a different shared_ptr.
so if it is not a BooleanExpPtr, which is what the constructor of
AndExp expects, how come i don't get a compiler error?

Thanks,

Matan
Jul 22 '05 #5
Fo************@ICQMail.com (Matan Nassau) wrote in message news:<3c**************************@posting.google. com>...
I have a constructor which accepts a shared_ptr:

typedef boost::shared_ptr<BooleanExpPtr> BooleanExpPtr;

AndExp::AndExp(BooleanExpPtr op1, BooleanExpPtr op2)
{
_operand1 = op1;
_operand2 = op2;
}

(see previous post for details regarding my definitions).
and I call it with

typedef boost::shared_ptr<VariableExp> VariableExpPtr;

VariableExpPtr x(new VariableExp("X"));
VariableExpPtr y(new VariableExp("Y"));
BooleanExpPtr expression(new AndExp(x, y));

and it works. it compiles nicely with no complaints.
how come? just let me understand the concept of the shared_ptr:
VariableExp derives from BooleanExp so VariableExp is a BooleanExp.
Good. But VariableExpPtr does /not/ derive from BooleanExpPtr as much
as I understand the shared_ptr; it is merely a different shared_ptr.
so if it is not a BooleanExpPtr, which is what the constructor of
AndExp expects, how come i don't get a compiler error?


Because boost::shared_ptr is designed to support Derived->Base
conversions just like classic pointers. There's a templated
implicit conversion. This is used to create a temporary
BooleanExpPtr from the VariableExpPtr. This temporary shares
the reference count with the original VariableExpPtr, so it
works as expected. The VariableExp isn't destroyed while the
BooleanExpPtr points to it.

This is a common advantage of boost libraries. The tricky cases have
been thought through for you.

Regards,
Michiel Salters
Jul 22 '05 #6
Fo************@ICQMail.com (Matan Nassau) wrote in message news:<3c**************************@posting.google. com>...
I have a constructor which accepts a shared_ptr:

typedef boost::shared_ptr<BooleanExpPtr> BooleanExpPtr;

AndExp::AndExp(BooleanExpPtr op1, BooleanExpPtr op2)
{
_operand1 = op1;
_operand2 = op2;
}

(see previous post for details regarding my definitions).
and I call it with

typedef boost::shared_ptr<VariableExp> VariableExpPtr;

VariableExpPtr x(new VariableExp("X"));
VariableExpPtr y(new VariableExp("Y"));
BooleanExpPtr expression(new AndExp(x, y));

and it works. it compiles nicely with no complaints.
how come? just let me understand the concept of the shared_ptr:
VariableExp derives from BooleanExp so VariableExp is a BooleanExp.
Good. But VariableExpPtr does /not/ derive from BooleanExpPtr as much
as I understand the shared_ptr; it is merely a different shared_ptr.
so if it is not a BooleanExpPtr, which is what the constructor of
AndExp expects, how come i don't get a compiler error?


Because boost::shared_ptr is designed to support Derived->Base
conversions just like classic pointers. There's a templated
implicit conversion. This is used to create a temporary
BooleanExpPtr from the VariableExpPtr. This temporary shares
the reference count with the original VariableExpPtr, so it
works as expected. The VariableExp isn't destroyed while the
BooleanExpPtr points to it.

This is a common advantage of boost libraries. The tricky cases have
been thought through for you.

Regards,
Michiel Salters
Jul 22 '05 #7

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

Similar topics

0
by: Ken | last post by:
Our tool control applicatioin is currently comprised of a .NET part written in C#, components written in C++ and a Lab View component. They are at different version levels. Not all composite...
0
by: Michael Andersson | last post by:
Given a set of classes class A { enum [ ID = 0x0001} }; class B { enum [ ID = 0x0002} }; class B { enum [ ID = 0x0004} }; I wish to generate a composite class, perhaps using something like...
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...
0
by: Satya Bojanapally | last post by:
Hi, I am unable to add a pager for this composite control. I had created a composite control in C#. The control is having 5 labels, one radio button and one DropDownList control. The composite...
10
by: dx | last post by:
I have the Microsoft Press: Developing Microsoft ASP.NET Server Controls and Components book. It's starting to shine some light on control development but there is something about composite...
2
by: pkpatil | last post by:
Hi, Can a private composite object in a class access private or protected members of base class? For e.g. class composite { void memberFunction(); };
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...
4
by: cmb99 | last post by:
I have a Symbol class, "MSFT". It has a bid and offer. "Dell" is also an instance of such a class. Sometimes, though, I want to combine two Symbol's into one, e.g. "MSFT" * "DELL", so that, I can...
8
by: ma740988 | last post by:
Data stored on a storage device is byte swapped. The data is big endian and my PC is little. At issue: There's a composite type ( a header ) at the front of the files that I'm trying to read in....
3
by: bob | last post by:
Hi, we are using the composite pattern which simply has a common abstract base class. Deriving from this class there is a Comp class, and a CompItem class, say. i.e. abstractBase | ...
0
by: erikbower65 | last post by:
Using CodiumAI's pr-agent is simple and powerful. Follow these steps: 1. Install CodiumAI CLI: Ensure Node.js is installed, then run 'npm install -g codiumai' in the terminal. 2. Connect to...
0
by: kcodez | last post by:
As a H5 game development enthusiast, I recently wrote a very interesting little game - Toy Claw ((http://claw.kjeek.com/))。Here I will summarize and share the development experience here, and hope it...
0
by: Taofi | last post by:
I try to insert a new record but the error message says the number of query names and destination fields are not the same This are my field names ID, Budgeted, Actual, Status and Differences ...
14
DJRhino1175
by: DJRhino1175 | last post by:
When I run this code I get an error, its Run-time error# 424 Object required...This is my first attempt at doing something like this. I test the entire code and it worked until I added this - If...
0
by: Rina0 | last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
5
by: DJRhino | last post by:
Private Sub CboDrawingID_BeforeUpdate(Cancel As Integer) If = 310029923 Or 310030138 Or 310030152 Or 310030346 Or 310030348 Or _ 310030356 Or 310030359 Or 310030362 Or...
0
by: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
0
by: Mushico | last post by:
How to calculate date of retirement from date of birth
2
by: DJRhino | last post by:
Was curious if anyone else was having this same issue or not.... I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...

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.