Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Address of destructor.

4 views
Skip to first unread message

Dhruv

unread,
Dec 24, 2003, 9:11:27 AM12/24/03
to
Is it legal to take the address of a destrutor? g++3.2 does not allow me
to do so. I needed this feature for this particular purpose: If anyone has
faces some such situation, and has found some solution, I'd like to know:

Reason:

I have a function 'foo' which returns a new T, and I want to implement
some sort of garbage collection on memory, so when the memory is freed by
the gc, then the object should also be destricted, because it might hold
some resource.

//Assume specializations for built-in-types.
template <typename T>
T *foo () {
//Hypothetical stuff below.
typedef void (*T::dtor_ptr) ();
T *temp = operator new (sizeof(T) + sizeof(dtor_ptr));
dtor_ptr dtor_fn = &T::~T;
dtor_ptr write_ = reinterpret_cast<dtor_ptr> (temp);
write_ = dtor_fn;
return reinterpret_cast<T*>
(reinterpret_cast<char*> (write_)+sizeof (dtor_ptr));
}

So that the deallocation function can just read off the function address
from the block passed to it, and call the dtor on the address following
the address of the dtor. But, then the type of the object is lost, and
lots of things are hopelessly wrong with approach, so I was wondering
whether this is actually possible?


Regards,
-Dhruv.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Hyman Rosen

unread,
Dec 24, 2003, 2:48:07 PM12/24/03
to
Dhruv wrote:
> Is it legal to take the address of a destrutor?

No. If you want the address of a function which will
call the destructor of an object, just do this:
template<class T> void destruct(T *o) { o->~T(); }
and store a pointer to destruct<T>.

Bronek Kozicki

unread,
Dec 26, 2003, 6:53:41 PM12/26/03
to
On 24 Dec 2003 09:11:27 -0500, Dhruv wrote:
> I have a function 'foo' which returns a new T, and I want to implement
> some sort of garbage collection on memory, so when the memory is freed by

std::auto_ptr has been created for this purpose. See example below:

std::auto_ptr<Element> create() const
{
// ... preparing constructor input data
return std::auto_ptr<Element>(new Element(input, data));
}

There might be situation where actual type of object is some class
derived from type being parameter of auto_ptr, and (at the same time)
this class does not have virtual destructor.

class Element {
// no virtual ~Element() defined!
}

std::auto_ptr<Element> create() const
{
class SomeElementA : public Element {};
// ... preparing constructor input data
{
return std::auto_ptr<Element>(new SomeElementA(input, data));
}
}

in this case you have undefined behaviour, as std::auto_ptr<Element>
will not call SomeElementA::~SomeElementA destructor when destroyed.

There are 3 cures for this problem:
1. define virtual destructor in Element class. Actual address of
destructor will be stored in virtual methods table and called at the
right time.

2. use boost::shared_ptr<Element>; this will store deleter (ie. call to
SomeElementA::~SomeElementA destructor) together with managed pointer
and call it when necessary.

3. take a look at my proposal of improved std::auto_ptr at
http://groups.google.com/groups?as_umsgid=1prjdsmef0v6t$.2kvyxem3pel1.dlg@40tude.net
It will do similar thing as shared_ptr, but much cheaper and preserving
std::auto_ptr sematics (strong ownership).


B.

Rani Sharoni

unread,
Dec 30, 2003, 12:20:26 AM12/30/03
to
Bronek Kozicki <br...@rubikon.pl> wrote in message
> There might be situation where actual type of object is some class
> derived from type being parameter of auto_ptr, and (at the same time)
> this class does not have virtual destructor.
>
> class Element {
> // no virtual ~Element() defined!
> }
>
> std::auto_ptr<Element> create() const
> {
> class SomeElementA : public Element {};
> // ... preparing constructor input data
> {
> return std::auto_ptr<Element>(new SomeElementA(input, data));
> }
> }
>
> in this case you have undefined behaviour, as std::auto_ptr<Element>
> will not call SomeElementA::~SomeElementA destructor when destroyed.
>
> There are 3 cures for this problem:
> 1. define virtual destructor in Element class. Actual address of
> destructor will be stored in virtual methods table and called at the
> right time.
>
> 2. use boost::shared_ptr<Element>; this will store deleter (ie. call to
> SomeElementA::~SomeElementA destructor) together with managed pointer
> and call it when necessary.

I don't think that you can handle local types in this way since they
are famously not allowed as template type arguments per 14.3.1/2.
Consider the following amusing code:
struct B {};
struct eat { template<typename T> eat(T); };

char* f(eat); // #1
long* f(B*); // #2

int main() {
struct A : B {} a;
long* p = f(&a); // #3 no SFINAE -> error
}

#2 has better rank than #1 but the instantiation of #1 declaration
(i.e. specialization) results with template type argument of local
type and this case doesn't fall under SFINAE which leads to ill-formed
declaration.

shared_ptr has template constructor for pointers and will also fail
for this case. Explicitly converting A to B before the initialization
will solve the problem but now we are back to the virtual destructor
requirement which, IMO, can't be avoided is such cases. Same goes for
your auto_ptr improvement suggestion since it relies on the knowing
the most derived type.



> 3. take a look at my proposal of improved std::auto_ptr at
> http://groups.google.com/groups?as_umsgid=1prjdsmef0v6t$.2kvyxem3pel1.dlg@40tude.net
> It will do similar thing as shared_ptr, but much cheaper and preserving
> std::auto_ptr sematics (strong ownership).

I like the idea and I think that compliant implementations have the
freedom to do the things you presented since optional parameters are
allowed per 17.4.4.4/2/2 (my const auto_ptr rejecting constructor and
template copying constructors are allowed per 17.4.4.4/2/3).

Rani

Bronek Kozicki

unread,
Jan 1, 2004, 7:37:53 AM1/1/04
to
On 30 Dec 2003 00:20:26 -0500, Rani Sharoni wrote:
> Bronek Kozicki <br...@rubikon.pl> wrote in message
> I don't think that you can handle local types in this way since they
> are famously not allowed as template type arguments per 14.3.1/2.

you are perfectly right, and I supplied wrong example. Let's imagine
that "class SomeElementA" is just nested class in private part of some
other class, and "create" is static function of this class.

>> 3. take a look at my proposal of improved std::auto_ptr at
>> http://groups.google.com/groups?as_umsgid=1prjdsmef0v6t$.2kvyxem3pel1.dlg@40tude.net
>> It will do similar thing as shared_ptr, but much cheaper and preserving
>> std::auto_ptr sematics (strong ownership).
>
> I like the idea and I think that compliant implementations have the
> freedom to do the things you presented since optional parameters are
> allowed per 17.4.4.4/2/2 (my const auto_ptr rejecting constructor and
> template copying constructors are allowed per 17.4.4.4/2/3).

Thanks. I'm glad to hear that someone likes it. What do you think about
providing bool test for auto_ptr, similar to bool_testable discussed on
boost ?


B.


template<class X> class auto_ptr
{
private:
// ...
struct _impl_ {int x;};
typedef int _impl_::*safe_bool;

public:
// ...
operator safe_bool() const
{
return (this->operator!() ? 0 : &_impl_::x);
}

bool operator! () const
{
return ptr_ == NULL;
}
};

Rani Sharoni

unread,
Jan 2, 2004, 8:04:53 AM1/2/04
to
Bronek Kozicki wrote:
> On 30 Dec 2003 00:20:26 -0500, Rani Sharoni wrote:
> >> 3. take a look at my proposal of improved std::auto_ptr at
> >>
>
http://groups.google.com/groups?as_umsgid=1prjdsmef0v6t$.2kvyxem3pel1.dlg@40tude.net
> >> It will do similar thing as shared_ptr, but much cheaper and
> >> preserving std::auto_ptr sematics (strong ownership).
> > I like the idea and I think that compliant implementations have the
> > freedom to do the things you presented since optional parameters
> > are allowed per 17.4.4.4/2/2 (my const auto_ptr rejecting
> > constructor and template copying constructors are allowed per
> 17.4.4.4/2/3).
>
> Thanks. I'm glad to hear that someone likes it. What do you think
> about
> providing bool test for auto_ptr, similar to bool_testable discussed
> on boost ?

IMO this is certainly more than welcomed enhancement that proved being
useful (read simplifying) in smart pointers like the boost ones.

Nevertheless since it's a relaxation we must be careful about backward
compatibility issues.
Consider the following:
char* f(auto_ptr<B>);
long* f(bool);

auto_ptr<D> dp;
char* p = f(dp);

Without the implicit conversions to bool the above code is (read suppose to
be) well formed. The relaxed auto_ptr will yield ambiguity since there are
two user defined conversions with the same rank. Notice that this problem is
only related to bool parameters (i.e. change bool to int in the above code
and the problem will disappear).
Adding additional tie break parameters (e.g. char and int) will lead to
well-formed code with different meaning. same problem with template vs
non-template.

IMO the above is rare and therefore the enhancement is welcomed.

Thanks,
Rani

0 new messages