473,396 Members | 2,052 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 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 2412
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: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
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,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
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...

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.