Re: Article on possible improvements to C++
On 27 Nov, 10:59, "Balog Pal" <p...@lib.hu> wrote:
"NickKeighley" <nick_keighley_nos...@hotmail.com>
<snip>
OTOH, the real way to make correct code is definitely not going by tha=
t
info but through using consistent RAII-like handling, and reviews enfo=
rcing
it.
I keep on seeing things like this. How exactly does RAII deal with
allocations that don't follow a simple [stack based] model?
Insert some example of the model you think problematic.
anything that doesn't follow a stack model. A graphical editor. A
mobile phone system. You are at the mercy of the end user as to when
objects are created and destroyed. With the phone system people can
drive into tunnels or JCBs (back-hoes) can dig up comms links (that
really happened once).
As test runs will hardly cover all possible paths including errors and
exceptions, so relying on the empty leak list from a random run is
nothing but illusion of being okay. While with trivial style it is eas=
y
to make leaks impossible.
so explain to me how I trivially remove all possible memory leaks from
my programs.
"Remove" is not the way. You start from nothing -- that is assumed
leak-free ;-) and add all the stuff in a way that can't leak. So yo=
ur
program is always leak-free.
ah, my computer science lecturer used to tell us that a blank piece of
paper had no bugs. Programmers then just went on to add bugs.
The style is like:
- 'delete' is forbidden in "client" code. It is privilige of the th=
e few
library classes that serve as managers. Like auto_ptr.
and who holds the auto-ptr?
- The result of every new goes immediately to one such manager.
That's about it.
these things always seem to solve the easy cases (ok they used to be
the very hard cases!) but not the hard cases.
Certainly there are a few cases where ownership is
transferred --
a few!
so look what happens to result of release(), Detach() and
similar calls, that is IME natural.
Same thing applies to other resources: files, handles, GDI resources, loc=
ks,
transactions.
except for transactions, yes
As an example, you may look some old Petzold examples to struggle with ra=
w
WIN API in pure C -- and see how the same thing looks using MFC's CFo=
nt,
CBrush and similar wrappers.
I've wrappered Win32 in C++. Yes, RAII makes life easier.
The difference is incredible in readability
and clearness. As a side effect DBWIN no longer explodes on any random
program reporting a zillion of lost resources.
If you want a very simple example,
no, I don't want a simple example
think a program that processes text
manipulating strings all its time. A C++ solution would use std::strin=
g,
(or any of the much better string classes). Doing all the passing-arou=
nd,
cutting, concatenating, etc.
consider a text editor that allows the user to delete text. Who
deletes the string that holds the deleted stuff and when. What if the
editor has Undo/Redo?
Without having a single new or other allocation in the *client* code of t=
he
program.
the client code is gonna have to do something to trigger the new. Call
a factory for instance.
While obvoiusly doing a zillion alllocations and deallocations.
Can you describe a way to introduce a leak?
forget to call the thing that triggers the delete.
Why invest in better patches instead of cure the problem at roots?
because you can't remove the problem at its root. If you want true
dynamic allocation then you need to trigger delete somehow. Unless you
add garbage collection to C++.
Sure you can, and many of us do it in practice. C++ has destructors th=
at
are called automaticly at well defined points
the points are not always so well defined.
-- and that automation can
reliably be used to do the deletes you need. All of them.
As, unless you start doing WTF things deliberately just to prove idiots'
I'm not *trying* to break things.
endless resources, destructors will be called matching constructors, and
when leaving a scope by *any* means.
but leaving scope is *not* the correct time to delete some objects!
CallManager::process_event (EventAP event)
{
CallAP call = 0;
if (is_new_call (event))
{
call = CallFactory::create_call (event);
CallList::add_call (call);
}
else
{
CallAp call = CallList::lookup_call (event);
}
call.process_event(event);
}
when this finishes the call should very definitly not be destroyed!
The CallManager (or some class this is delegated to has to track what
goes into CallList (the list of currently active calls) and also be
careful about rmoving things from it- when they are destroyed.
So the programmer's responsibility
is just to not leave non-managed resources around.
oh, *that* all!
(Certainly for certain tasks you can insert GC too, I didn;t work with su=
ch
problem yet, but read success stories.)
I've never used garbage collection in C++ either.
--
Nick Keighley
The world you perceive is drastically simplified model of the real
world
(Herbert Simon)