Re: rtti
On May 3, 10:41 am, =C3=96=C3=B6 Tiib <oot...@hot.ee> wrote:
On May 3, 2:09 am, James Kanze <james.ka...@gmail.com> wrote:
On May 2, 9:00 pm, Chameleon <cham_...@hotmail.com> wrote:
=CE=A3=CF=84=CE=B9=CF=82 02 =CE=9C=CE=B1=CF=8A 2011 14:05, =CE=BF/=CE=
=B7 =C3=96=C3=B6 Tiib =CE=AD=CE=B3=CF=81=CE=B1=CF=88=CE=B5:
On May 2, 5:03 am, Chameleon<cham_...@hotmail.com> wrote:
I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` fr=
om
base class `Relation`.
I want to put all of these in a `vector<Relation>` but they have
different size, so, I create a `union AnyRelation` and I put all o=
f
derived classes inside this union, and the vector become
`vector<AnyRelation>`.
When I want to check what type the derived class is, I use `typeid=
`.
It is asking for difficulties. C++0x changed the union a bit but i
still dislike it.
Is there a better approach, or I am going right?
I suspect your way it won't work.
1) More common alternatives:
vector<boost::shared_ptr<Relation> >
vector<tr1::unique_ptr<Relation> >
2) Just
vector<Relation*>
Create large number of small individual objects in heap is overhead.
It sounds like Java to me.
The reason Java works like this is that it more or less assumes
(or almost requires) that every object is polymorphic. From
what you've described, that's the case you're in. As soon as
polymorphism comes into play, C++ starts allocating dynamically
as well.
The whole concern about small allocations sounds a bit premature for
me.
Agreed.
Marcel M=C3=BCller suggested something like:
vector<boost::variant<Angle, Azimuth, Distance, Height>
That will not allocate lot of small objects. My experience is that
boost::variant does not also fit for polymorphic classes (but is
certainly better than union).
Another name for "variant" is discriminate union:-). The
original poster had them all deriving from a common base class,
so I assumed polymorphism, but depending on the design, a
discriminate union could be a valid alternative. (But one or
the other: if you use boost::variant, there's no sense in
keeping the common base class.)
works for those who do not want dependency on boost or C++0x
extensions. It is more error-prone when dealing with raw
pointers so enwrap it into something.
There are very few things as error prone as boost::shared_ptr.
At least for the sort of things one usually allocates
dynamically; his case may be the exception (but he's not told us
enough about the derived types to be sure).
I am not sure why shared_ptr is error prone.
It's too easy to end up with the memory being deleted too soon,
because you've made a shared_ptr twice from the same raw
pointer, or to end up with memory leaks, because of cycles.
It is a tool like any other tool and it is *wrong* to use it
at numerous places. Who knows how it is for OP's problem.
Thats why i gave several options. If it fits the design then i
would use shared_ptr instead of raw pointer.
Used like that, with an understanding of its weaknesses, it's a
very effective tool; I use it myself in such cases. (More
often, I'll use my own reference counted pointer, however.
Simply because I had it and was using it before boost came
along, and I'm used to it.) But because it's so often
recommended as a silver bullet, to be used automatically without
thinking, one feels obliged to repeat the usual warnings.
3) You can remove the exposed polymorphism by using pimpl idiom so
Relation becomes envelope class and `Angle`, `Azimuth`, `Distance`=
,
`Height` are its hidden internal variants of implementation. Then
vector<Relation> works fine.
But he still ends up with a lot of small allocations:-).
If it becomes concern then OP may use boost::pool for fast dynamic
allocations (with pimpl it works great) also he can use other nice
optimizations with pimpl (like lazy copy-on-write).
A lot of implementations of malloc will in fact use a pool
allocator for small allocations. The real point is (and I'm
sure you agree): don't worry about it until it is a problem (if
it ever is), and then solve the exact problem, based on profiler
output.
From the names, I suspect that a single class, with a
discriminator indicating how to interpret the contents, and
perhaps a union with the actual data, might be appropriate.
Might be---one really can't say without knowing more about the
applications.
Yes, that is also possibility. It can however result with hard-to-
maintain C-style switch-case polymorphism in unskilled hands.
In unskilled hands, polymorphism can also result in hard to
maintain code:-). This suggestion is really just a simplified
variant of the boost::variant solution; in both, you have to
deal with a switch (or chained else/if, or possibly, a
map<pair<TypeId, TypeId>, someFunctionType>). Usually (based on
my experience, at least), polymorphism will result in a cleaner
solution, but there are exceptions.
--
James Kanze