0

I have the following classes:

class State
{
  protected:
    Vec3D accel;
    Vec3D gyro;
    Vec3D gps;
    float reward;
  public:
    boost::ptr_vector<Action> actions;
    ...
    virtual bool isTerm();
}

class guState : public State
{  
    float gps_stand_thres;
    float gps_down_thres;
  public:
    guState(Agent &A,ACTION_MODE &m);
    bool isTerm();
};

There are other classes which all inherit from State. Their differences solely lie on how they evaluate isTerm() which depends on behavior. I would rather not use virtual functions bur override function isTerm, if it wasn't for the fact that there are a few other templated classes which are designed to work with all sorts of State-derived classes. One of them is Policy:

template <class S>
class Policy
{ 
  protected:    
    float QValue;
    S *state;
    S *nextState;
  public:
    ...
    template <class P>
    void updateOptimal(boost::ptr_vector<P> &policies);
}

updateOptimal has to obtain A State-derived class (depending on behavior), up-cast from a State *ptr to whatever the S-type being currently used is, in order to search for policies for that state. Now, because State-derived classes are polymorphic, I assumed it was the right thing to do:

S *s = dynamic_cast<S *>(iter->getNextState());

where the iter is an iterator of Actions and each action has a pointer of State *nextstate; action->nextstate is set at some other point:

action->setNextState(dynamic_cast<State *>(state)); 

I could template the entire class Action, in order to avoid using State *nextstate; and use S *nextstate; but that would require an enormous amount of changes throughout the project.

Reading the casting tutorial on cplusplus.com it is my understanding that it is best to use dynamic_cast because it does a type check before up or down casting. However in the following code after casting I do not do anything to the up casted state other than use it for searching:

P *temp_pol = var::findPolicy(policies,s);

where findPolicy is:

template <class P, class S>
P* findPolicy(boost::ptr_vector<P> &policies,S *state);
  • Would it be ok to skip safety checks, and use a static cast ? I have tried it, and it compiles.
  • Would it be ok to skip checks altogether, and do a reinterpret_cast ? I have also tried it and it compiles.
  • What is the penalty for doing a dynamic_cast ? I know theres a small overhead, but is it anything serious ?
  • Is there a way to upcast from State *ptr to S-type *ptr without using a polymorphic class (avoiding the virtual function and simply override it)?
Ælex
  • 14,432
  • 20
  • 88
  • 129
  • 4
    *I would rather not use virtual functions* - why do you not want to use the one tool that is designed to solve your problem? – Björn Pollex Jul 20 '11 at 18:50
  • Because it is my understanding that it also increases overhead and size, and performance is an issue. – Ælex Jul 20 '11 at 18:51
  • 2
    While this is true, you should do some profiling to make sure that such optimizations are really worth it, as the overhead is very small, and would only have an impact if you have a massive amount of polymorphic objects and virtual function calls. These mechanism are extremely optimized. – Björn Pollex Jul 20 '11 at 18:52
  • Also, if you are really care that much about the performance, go with the templates, even if they are a lot of work. This is probably as fast as you can get. – Björn Pollex Jul 20 '11 at 18:54
  • That exactly is my issue, there are billions of these objects, they are states for a robot, and as you understand even the slightest amount of gain can be helpful. Also it is my understanding that RTTI for dynamic_cast has a somewhat small penalty ? – Ælex Jul 20 '11 at 18:55
  • 3
    @Alex Using `dynamic_cast` gains you *nothing* over virtual functions. In fact, the former relies on the existence of the latter (more precisely, on the existence of a virtual method table). – Konrad Rudolph Jul 20 '11 at 19:03
  • 1
    @Alex: the cost of virtual dispatch is very small, and will only affect the system if most of your work is actually calling functions that do basically nothing. It is true that there is a small penalty but that penalty is so small that I doubt that it affects anything. **Measure** first, then decide where the bottleneck is and tackle it. As of the cost of RTTI and `dynamic_cast`, the cost of a downcast with `dynamic_cast` is much higher than the cost of a dynamic dispatch (you should not be *downcasting* in your code, that is what virtual functions are for!). – David Rodríguez - dribeas Jul 20 '11 at 19:07
  • 1
    @Alex - The rule for virtual functions is: "If you need them, you need them". If there is an easy to use and very fast method for virtual dispatch, why do you believe the compiler isn't using exactly that method? It is! – Bo Persson Jul 20 '11 at 19:33

1 Answers1

4

The difference between static_cast and dynamic_cast is that an invalid static_cast is undefined behavior, while an invalid dynamic_cast results in a null-pointer or a bad_cast-exception (if you cast references). The penalty for a dynamic_cast is a type-check during runtime, and increased code-size due to RTTI.

So, if you are sure that the cast is always fine, you can safely use static_cast. Using reinterpret_cast would not give you any performance-improvement over static_cast, so you shouldn't use it here.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • 2
    +1 `reinterpret_cast` will not yield any advantage, plus it can really mess up the system. There is no guarantee that the base subobject and the derived object are aligned in the same memory address (the base could have an offset) and a reinterpret cast will completely ignore that, causing undefined behavior – David Rodríguez - dribeas Jul 20 '11 at 19:21