class Base // abstract class
{
public:
virtual ~Base();
void Destroy() { delete this; }
};
class Derived: public base
{
protected:
~Derived(); //User must allocate on the heap and destroy using
Base::Destroy
};
But that does not prevent anybody from deriving from Base and declaring the
destructor as public, thus causing unpleasant behavior when Destroy is
called.
Ury.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.20
Make the base class destructor protected and virtual.
class Base // abstract class
{
protected:
virtual ~Base();
public:
void Destroy() { delete this; }
};
However, I'm very suspicious of this code pattern.
Every time I've seen it there was a better
solution that didn't involve self-deleting objects,
and thus eliminated the restriction that instances of some
class had to be on the heap.
Yes, and how does that solve the OP's problem. He wants a base class all
of whose derived variants must also be on the heap. Maybe I am being
dense but I do not see how that solves this problem. IIRC protected
dtors are accessible to derived classes.
--
Francis Glassborow
Check out the ACCU Spring Conference 2002
4 Days, 4 tracks, 4+ languages, World class speakers
For details see: http://www.accu.org/events/public/accu0204.htm
> [...]
Apparently you misunderstood the text: The FAQ does not suggest that
the destructor is made protected but that the _constructor_ be
private.
I posted the same solution as given in the FAQ and Francis is
correct; it does not solve the OP's problem. I don't
believe that his problem can be solved -- if the base class allows
public derivation then it will be possible to write a derived class with a
public constructor. I would advise the OP to re-examine his need
for such a class.
Sure, but that makes no difference (other than you better make sure you
have remembered to declare a private copy ctor as well.) Could we focus
on ideas that might solve his problem which is not the one in the FAQ.
He wants to force all derived classes off the stack. I would be
interested in an answer because I do not know of one. A protected ctor
is AFAIR, accessible to derived class ctors, and private ones simply
prevent direct construction of both the base and derived objects.
--
Francis Glassborow
Check out the ACCU Spring Conference 2002
4 Days, 4 tracks, 4+ languages, World class speakers
For details see: http://www.accu.org/events/public/accu0204.htm
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Just a quick thought.
The best way to do a compile-time enforcement is to prohibit
working with objects directly, and use some kind of smart pointers,
that will accept/work only with objects with dynamic storage
duration.
If a runtime enforcement would be acceptable and it was acceptable
to prohibit derived classes to overload operator new, there is a simple
and obvious solution (below).
It's somewhat fragile to my sense, but it works.
However, I suspect that there couldn't be a C++ standard conforming
compile time enforcement, just because there is explicitly defined
"stack space" in C++ standard (as opposed to free store).
(I hardly believe we could use "stack unwinding" for these purposes.)
So the OP's question is about differentiating objects with automatic
or static storage duration and objects with dynamic storage duration
at compile time.
AFAIK, the only relevant difference is the way objects with
dynamic storage duration get created/destroyed (3.7.3/1),
but I don't see how one can exploit it at compile time.
So I would be interested in an answer as well,
because I couldn't think of one.
A runtime enforcement helper sample:
#include <cassert>
#include <cstddef>
struct rt_heapalloc_check
{
virtual ~rt_heapalloc_check() {}
void* operator new(std::size_t sz) { ++heap_check; return ::operator new(sz); }
void operator delete(void* p) { ::operator delete(p); }
protected:
rt_heapalloc_check() { assert(--heap_check==0); }
private:
static int heap_check;
};
int rt_heapalloc_check::heap_check = 0;
struct foo : rt_heapalloc_check {};
int main()
{
//B b; //at runtime this will fail an assertion
B* b= new B; //works fine
return 0;
}
Sincerely,
Ruslan Abdikeev