Re: Dynamically allocated classes
Ulrich Eckhardt wrote:
kanze wrote:
Ulrich Eckhardt wrote:
Theo Richter wrote:
item* pencil = new item;
Two things here:
- Don't use new unless you have to, this is not Java.
This depends on the type of the object. My impression is
that Items are entity objects, not simply values. If that
is the case, they will normally be dyamically allocated.
True. You cannot pass entities 'by value' (i.e. using copying)
so the 'unless you have to' doesn't apply. Other than that,
the fact that something resembles a real-world object doesn't
mean that the representation inside a program must be an
entity, in particular for an item in a stockroom it will often
be just a recordset with some predefined fields like
article-number, vendor-ID and a description (i.e. what you
would put into a database).
And the quantity, which can be modified. At least, the name
item suggests that to me. But of course, it depends on the
application, and you're right that not every real world object
is an entity (or vice versa -- entity objects can be very
artificial to the software implementation of the application).
- Don't use raw pointers but some smart pointer type.
That's pretty strange advice. About 80% of my pointers are
raw pointers. I only use smart pointers when I need some
special semantics, which isn't usually the case.
If you're not using garbage collection, then you'll probably
need smart pointers more frequently, but still not
systematically. In practice, for example, entity objects
(which, as mentionned above, should be most of your
dynamically allocated objects) should rarely be managed by
smart pointers.
Hmmm. I guess using GC shifts the code towards using raw
pointers.
Well, it eliminates one frequent use. But my experience is that
smart pointers don't really cover all cases of lifetime very
well anyway. Even without GC, sometimes they're appropriate,
and sometimes they aren't. In particular, I find it rare for
them to be appropriate for entity objects (whose lifetime is, or
should be, controled by external events, and not whether someone
happens to have a pointer to it).
Otherwise, I see two cases of pointers:
1. pointers to dynamically allocated storage
Not that often, really. Most of the time, non-entity objects
are allocated on the stack. And entity objects have explicit
lifetime management -- it's not the pointers which manage the
object, but the object itself which notifies all other objects
which hold pointers to it. You can sometimes use weak pointers
for this, but not in general, since resetting the pointer to
null is typically not enough -- you have to remove it from a
container (or the container grows infinitly), or react in some
other way.
The result is that I've not found a smart pointer that really
works well with entity objects that decide their own lifetimes.
And that I allocate very few other objects dynamically. I have
used smart pointers at times -- for temporary agents, for
example, that need to be polymorphic, and which have no need of
deterministic destruction. But garbage collection is the
preferred solution for that. And of course, there are lots of
smart pointers which do more than just manage memory -- I use
them a lot in transaction management or threading, for example.
(I use auto_ptr almost systematically in my threading interfaces
-- including when I'm using garbage collection. I don't think I
ever used it elsewhere, however.)
2. pointers that are passed to legacy APIs or that reference
an optional object (like the parameter to time()).
Given that those are often pointers to local variables...
For the second category, smart pointers make no sense, but for
the former I use smart pointers almost exclusively.
Object X receives an event which indicates that its lifetime has
ended. The obvious way to implement this behavior is "delete
this". How do you do this with smart pointers. (With
boost::shared_ptr, the only thing I can think of is some sort of
dispose method, ? la Java -- with its accompanying zombie
object.)
The only regular exceptions I regularly make is when
implementing PIMPLs (because auto_ptr can't be used,
shared_ptr has unnecessary overhead and there is no sharing
going on and it's just too simple to do get it wrong) and
sometimes for the handful of permanent, global objects that
make up my programs (I sometimes don't even bother deleting
them).
Interesting. Boost::scoped_ptr would seem very appropriate for
the pimpl. Not enough benefit to justify introducing smart
pointers into an application which otherwise makes very little
or no use of them (as you say, it's very simple), but certainly
the way I would go if I were making extensive use of Boost's
smart pointers otherwise.
How do you get such a high percentage of raw pointers?
By only allocating things which have an explicit lifetime
dynamically:-).
Also, I guess that exception safety is not one of the 'special
semantics' you use smart pointers for but a normal semantic
that all your code has, right?
Curiously, I've not found exception safety to be that big a
problem. Local objects (e.g. value objects like std::string) do
manage memory, but they generally do so explicitly -- and as you
say, things like the pimpl idiom are dead easy to get right.
Value objects which do require more than a single dynamic
resource do generally end up using a smart pointer to manage
them, but in my experience, they aren't that frequent. I use
RAII extensively, but the resources involved are usually things
like locks and temporary files -- the RAII isn't what I would
call a smart pointer, and doesn't overload either * or ->.
Before garbage collection, I'd guess that about half my smart
pointers were used for managing temporary objects -- those which
needed to be polymorphic, for example. But that still didn't
account for a majority of my pointers.
On one project, about four or five years ago, I decided to use
smart pointers exclusively; I too felt that that was the way to
go. My experience was that it just didn't work. Smart pointers
solve some problems, but cause a lot of others. Today, I still
use them, but only when they solve more problems than they
create. With garbage collection, in fact, only when they solve
some very specific problem; e.g. not allowing access in the
originating thread once it has transferred ownership to another
thread.
--
James Kanze GABI Software
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]