Re: private destructor and templates
Ben Voigt wrote:
"Tom Widmer [VC++ MVP]" <tom_usenet@hotmail.com> wrote in message
news:OZkk4618GHA.3740@TK2MSFTNGP05.phx.gbl...
Ben Voigt wrote:
I have a POD type with a private destructor. There are a whole hierarchy
of derived POD types, all meant to be freed using a public member
function Destroy in the base class. I get warning C4624. I read the
description, decided that it's exactly what I want, and ignored the
warning.
As said by others, your class becomes a non-POD as soon as you declare a
destructor. Additionally, derived classes are never POD types.
Ok, I'm not really caring about being POD. I care about being able to use
and destroy it non-virtually.
You can't do that portably even for POD types, unless you switch from
new/delete to malloc/free. More on that further down.
Now I'm trying to inherit using a template. Instead of "destructor could
not be generated because a base class destructor is inaccessible", I now
have an error C2248 <name of base destructor> "cannot access private
member". Is this correct or a bug?
It depends on whether your code is attempting to use the derived class
destructor (e.g. a call to delete will do that).
One of the derived classes had a gcroot member (to carry System::Exception
objects between threads). Not calling the destructor on that would be bad,
so now I'm explicitly setting it to nullptr before letting the base class
destroy it. What I will probably end up doing is formatting an error
message using Environment::StackTrace and passing that as raw UNICODE
characters.
I'm passing information between threads (one managed, one not) and if
something gets mixed up so there are still messages in flight (PostMessage)
when I call DestroyWindow, I'd like to not lose anything more than just
leaking a small buffer object (up to 200 bytes) on the heap. Since the .NET
gc can't track pointers inside message queues, this is how I've chosen to do
it.
That is in violation of the docs for PostMessage:
"If you send a message in the range below WM_USER to the asynchronous
message functions (PostMessage, SendNotifyMessage, and
SendMessageCallback), its message parameters cannot include pointers.
Otherwise, the operation will fail. The functions will return before the
receiving thread has had a chance to process the message and the sender
will free the memory before it is used."
In other words, you shouldn't fire off pointers to a window and expect
the window to delete them. Instead, you should use SendMessage, and
delete them yourself. This then avoids the whole issue.
Incidentally, this is why it's very important to me to avoid virtual calls
to anything. Anyone could drop messages into my queue with an arbitrary
LPARAM.
I don't understand that.
Toward that end, is it possible to filter WM_TIMER messages from being
passed to DispatchMessage in a .NET app?
Sorry, I've no .NET expertise.
I don't want the compiler to generate a
destructor for the base class,
But you've written a destructor - it even does something (calls
FreeAgent();).
Sorry, I meant I didn't want the compiler to generate destructors for the
derived classes.
Ahh, ok.
I won't declare any variables on the stack
and I will use the base Destroy function to deallocate it.
If you won't declare any variables on the stack, just drop your
declaration of a destructor - it isn't needed. Instead, to prevent
accidental external delete calls, you could declare a class operator new
public and operator delete protected, which shouldn't affect your POD
Sadly, protected operator delete causes a compile error at every use of
operator new.
I think this is in case a constructor throws -- the instance isn't
constructed at that point, so the destructor needn't be accessible. But
operator delete needs to be. (/me frowns)
Actually that is it, because marking derived constructors nothrow with
throw() makes the error go away.
Ahh, yes. I didn't realise the derived classes have destructors (which
is yet another violation of the requirements on POD data).
That is problematic, since your destructor isn't virtual. You can't
destroy an object through a base class pointer unless it has a virtual
destructor.
If all derived types just add additional POD fields, then I wouldn't need to
destroy it virtually.
Calling delete with the wrong type is illegal C++, unless the destructor
is virtual. It happens to work on some compilers and versions, but not
necessarily all, since the compiler is at liberty to use the type of the
deleted object to determine the size of the allocation that created it.
Also, a debugging implementation might check that constructed objects
have their destructors run.
Based on what you've said, the easiest option would be to stop using
PostMessage and instead destroy messages at the sending site. If you
can't do that, you are probably best off moving to using real POD
objects, dropping your use of new and delete expressions, and using
::operator new and ::operator delete (or malloc and free), which work
fine with raw memory, and don't care about pointer types or destructors.
If you want more standards compliant code, you could replace
constructors with initialization functions, and drop inheritence
entirely (making your Destroy function a free function).
It seems to me that you're conflating OO and C style programming in an
unnecessary and confusing way.
Tom