rtti

C

Chameleon

Hi!
I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
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 of
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`.

Is there a better approach, or I am going right?

Another try, is to put every derived class in its own vector:
vector<Azimuth>
vector<Angle>
vector<Distance>
and so on.
and in a `vector<Relation>` I can use references to real objects.
With this approach I can avoid the `typeid` because I can check if
pointer of derived class object belongs to a specific `vector`.


And a final question:
Its better to create my own rtti, or to use build-in? (for speed)
My own rtti:
------------
class A {
A() : rtti(0) {}
int rtti;
int getRTTI() { return rtti; }
bool isB() { return rtti == 1; }
virtual ~A() {}
};
class B : public A {
B() { rtti = 1; }
};
 
P

Pavel

Chameleon said:
Hi!
I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
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 of
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`.

Is there a better approach, or I am going right?
Mostly theoretically, I can see a situation where the derived classes have
different alignment from the derived class. Thus, even if the hierarchy only
uses single inheritance, you would have to know the type before accessing the
object in the union (and as you do it to learn the type, you have a
chicken-and-egg issue)..
Another try, is to put every derived class in its own vector:
vector<Azimuth>
vector<Angle>
vector<Distance>
and so on.
and in a `vector<Relation>` I can use references to real objects.
With this approach I can avoid the `typeid` because I can check if
pointer of derived class object belongs to a specific `vector`. This will work.


And a final question:
Its better to create my own rtti, or to use build-in? (for speed)
My own rtti:
------------
class A {
A() : rtti(0) {}
int rtti;
int getRTTI() { return rtti; }
bool isB() { return rtti == 1; }
virtual ~A() {}
};
class B : public A {
B() { rtti = 1; }
};
If you have virtual destructor anyway, you can save an int by defining a virtual
instead
virtual int getRTTI() const { return <type>; }

Using built-in RTTI would work with less effort (although maybe with same
performance).

Please note I do not comment on your design because I do not know its purpose.
Often, however, the designs directly checking the types are suspects. It's
*usually* better make class objects do things by calling virtual functions than
checking their types and do things with them. Again, not knowing your goal, I
can't say with confidence this will work better in your case but you might want
to give it a look.

HTH,
-Pavel
 
M

Marcel Müller

Chameleon said:
Hi!
I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
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 of
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`.

typeid won't help you, as you must not access any member of a union
except for the one you put into the union. So typeid would enable you to
store a fixed set of types in a predefined union. (Anything else would
be an exception.) But how do you extract the classes from the union
without accessing the wrong one?
Is there a better approach, or I am going right?

Absolutely. If you really need polymorphic members in a vector, you
won't come around using pointer or smart pointers and separate allocations.

If you are restricted to only a few types, have a look at
boost::variant. It addresses almost exactly what you want to do.

Another try, is to put every derived class in its own vector:
vector<Azimuth>
vector<Angle>
vector<Distance>
and so on.
and in a `vector<Relation>` I can use references to real objects.
With this approach I can avoid the `typeid` because I can check if
pointer of derived class object belongs to a specific `vector`.

I would prefer to use a vector<Relation> that owns it's objects in some
way (shared or not).

And a final question:
Its better to create my own rtti, or to use build-in? (for speed)
My own rtti:
------------
class A {
A() : rtti(0) {}
int rtti;
int getRTTI() { return rtti; }
bool isB() { return rtti == 1; }
virtual ~A() {}
};
class B : public A {
B() { rtti = 1; }
};

This will primarily create a memory overhead, since unlike you almost no
compiler stores any RTTI per instance. As long as you use RTTI only for
equality comparison it is most likely faster than anything you could
write, because effectively only slots of the vtable are compared. There
is no virtual function call and no linear memory overhead.


Marcel
 
Ö

Öö Tiib

I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
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 of
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*>

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.

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 said:
Another try, is to put every derived class in its own vector:
vector<Azimuth>
vector<Angle>
vector<Distance>
and so on.

That loses polymorphism over common interface Relation and you will
have several containers to manage.
and in a `vector<Relation>` I can use references to real objects.

References can not be stored in vector. Also you should avoid storing
iterators or references or pointers to elements of vector. These get
invalid if you insert, erase or push_back into vector.
With this approach I can avoid the `typeid` because I can check if
pointer of derived class object belongs to a specific `vector`.

And a final question:
Its better to create my own rtti, or to use build-in? (for speed)
My own rtti:
------------
class A {
        A() : rtti(0) {}
        int rtti;
        int getRTTI() { return rtti; }
        bool isB() { return rtti == 1; }
        virtual ~A() {}};

class B : public A {
        B() { rtti = 1; }
};

Nah ... avoid magic numbers and avoid writing things yourself that are
present in language. The people writing compilers are way over average
skilled and their user base is large so their defects will be most
likely discovered and fixed before your software reaches your end
users.

Use built-in RTTI when you need to. Beware that you should avoid
directly using RTTI as lot you can. Using RTTI too lot indicates weak
design. dynamic_cast can be useful for acquiring (or checking
presence of) other interfaces when having an interface pointer. For
typeid there are too few good use cases besides debugging and
troubleshooting.
 
C

Chameleon

Στις 02 Μαϊ 2011 14:05, ο/η Öö Tiib έγÏαψε:
It is asking for difficulties. C++0x changed the union a bit but i
still dislike it.


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.
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.

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.

My approach a little bit similar:
Every of 5 derived classes in its own vector. (Instead of every single
object in a new block in heap)
A big vector with envelope class for derived classes implementing the
operator* to access base class which has the complete functionality.
Envelope class has the type of derivative class and the index in its vector.

The problem is that I cannot use only one derived class to do something,
but different derived classes together. E.g. Distance and Angle (to
describe a new point) or angle and angle, or distance and distance and
clockwise.

And after I will use all of these as springs linear (Distance, Height)
or angular (Angle, Azimuth) to minimize the error.
 
J

James Kanze

I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
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 of
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`.
Is there a better approach, or I am going right?

Well, there's one major problem with your approach. It isn't
legal C++, and won't compile. At least assuming that Relation
has any virtual functions (and it should, otherwise, there's no
point in the derivation). What you can do is use something like
boost::variant, or even boost::any, but usually (not always),
the need for such a solution is indicative of a design error.
Another try, is to put every derived class in its own vector:
vector<Azimuth>
vector<Angle>
vector<Distance>
and so on.
and in a `vector<Relation>` I can use references to real objects.
With this approach I can avoid the `typeid` because I can check if
pointer of derived class object belongs to a specific `vector`.

The real question is what you are doing with the typeid to begin
with. You've not described the problem in enough detail, or
rather at a high enough level, for us to make any concrete
suggestions, but in most cases, if Azimuth implements Relation,
client code should be able to deal with just Relation, without
knowing that this particular Relation is an Azimuth. (Again,
there are exceptions, but they are few and far between. And
generally only concern a single subset of the derived classes.)
And a final question:
Its better to create my own rtti, or to use build-in? (for speed)
My own rtti:
------------
class A {
A() : rtti(0) {}
int rtti;
int getRTTI() { return rtti; }
bool isB() { return rtti == 1; }
virtual ~A() {}};
class B : public A {
B() { rtti = 1; }
};

In general, it's better to only use virtual functions. If some
of the derived classes have to implement an extended interface,
then I'd probably go with dynamic_cast until the profiler showed
it to be a problem. If it is a performance problem, and the
design really does require such, then you can consider something
like:

class Base
{
// ...
virtual Extended* getExtended() { return NULL; }
// ...
};

class Extended : public Base
{
virtual Extended* getExtended() { return this; }
// ...
};

Those classes which implement the extended interface derived
from Extended; those which don't, don't.

And for better or for worse, once polymorphism enters into the
scene, you're going to have to deal with pointers and dynamic
allocation. Since, based on the names, I'd guess that these are
really "value" type objects (which you'ld copy, and never
allocate dynamically if the polymorphism wasn't involved), and
they probably don't contain pointers to other objects (so you
can't get cycles), you can consider using some sort of reference
counting pointer; boost::shared_ptr, or better yet, some sort of
invasive pointer (and have Relation contain the counter);
alternatively, if you make all of the constructors private,
use factory methods which return the smart pointers, and none of
the types ever call any function which might take a pointer to
the object itself, you can probably use boost::shared_ptr
without too many problems.
 
J

James Kanze

Στις 02 Μαϊ 2011 14:05, ο/η Öö Tiib έγÏαψε:
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.

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).

But he still ends up with a lot of small allocations:).

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.
My approach a little bit similar:
Every of 5 derived classes in its own vector. (Instead of every single
object in a new block in heap)
A big vector with envelope class for derived classes implementing the
operator* to access base class which has the complete functionality.
Envelope class has the type of derivative class and the index in its vector.
The problem is that I cannot use only one derived class to do something,
but different derived classes together. E.g. Distance and Angle (to
describe a new point) or angle and angle, or distance and distance and
clockwise.
And after I will use all of these as springs linear (Distance, Height)
or angular (Angle, Azimuth) to minimize the error.

I'm not sure I've understood what you're trying to do, so this
might be complete rubish, but it vaguely sounds like you're
trying to maintain a position (relative or absolute?) in several
different formats. The usual solution here is to unify the
format inside the class, and add manupulators along the lines of
changeAzimut, etc.
 
J

Juha Nieminen

Chameleon said:
Create large number of small individual objects in heap is overhead.

Sometimes you simply don't have a choice. Dynamic polymorphism usually
means that you must allocate on the heap. Depending on how often and
how many you need to do it, the overhead may well be inconsequential.
 
Ö

Öö Tiib

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. Marcel Müller 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).
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 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.
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).
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. I would
first try to move real polymorphism to implementation detail.
 
Ö

Öö Tiib

Στις 02 Μαϊ 2011 14:05, ο/η Öö Tiib έγÏαψε:


My approach a little bit similar:
Every of 5 derived classes in its own vector. (Instead of every single
object in a new block in heap)
A big vector with envelope class for derived classes implementing the
operator* to access base class which has the complete functionality.
Envelope class has the type of derivative class and the index in its vector.

The "own vectors" in your design sound like custom memory management.
If so then use things designed for memory management like boost::pool.
The problem is that I cannot use only one derived class to do something,
but different derived classes together. E.g. Distance and Angle (to
describe a new point) or angle and angle, or distance and distance and
clockwise.

And after I will use all of these as springs linear (Distance, Height)
or angular (Angle, Azimuth) to minimize the error.

It feels that the Distance, Height, Angle and Azimuth are not
descendants of generic Relation (that "does something") but its
possible components. So actually you should have LinearRelation and
AngularRelation derived from Relation?
 
J

James Kanze

The whole concern about small allocations sounds a bit premature for
me.
Agreed.

Marcel Müller 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.)
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.
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.
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top