1

I am a person, who loves to go deep into nitty-gritty details. This time I created really simple functionality, which I called "Scenario" (look under for code). First I will present to you my vision of it:

struct ScenarioContext
{ virtual ~ScenarioContext() = default; };

struct IScenarioStep
{
    virtual ~IScenarioStep() = default;
    virtual void run( ScenarioContext& ) = 0;
};

struct ScenarioContainer final
{
    std::list<std::unique_ptr<IScenarioStep>> m_scenarioStepList;
};

struct Scenario
{
    explicit Scenario( ScenarioContainer&&, std::unique_ptr<ScenarioContext>&& = nullptr );

    void execute(); // Runs the steps one by one and passes context ref to steps

    std::unique_ptr<ScenarioContext> m_context;
    ScenarioContainer                m_container;
};

And now example "ScenarioStep" implementation:

struct SimpleContext
    : ScenarioContext
{
    bool isFirstStepDone  = false;
    bool isSecondStepDone = false;
    bool isThirdStepDone  = false;
};

struct ScenarioStep
    : IScenarioStep
{
    void run(ScenarioContext& ctx) override
    {
        auto THE_ISSUE = dynamic_cast<SimpleContext&>(ctx);
    }

};

And here I came to the conclusion, that there is absolutely no way that user/developer might get the wrong type of context. Is it wrong to use here reinterpret_cast? If so why? The absolute zero cost is so tempting here.

If not reinterpret_cast, what about static_cast?

I am really confused about all this "dont's" of tools that we have at our disposal.

Black
  • 312
  • 2
  • 15
  • 3
    Whenever you can use a different `*_cast` than the `reinterpret_cast` the rule is to use that `*_cast`. And whenever you think you have the need to use `reinterpret_cast` you should think about if your code design is correct. With `reinterpret_cast(x)` you force the compiler to treat `x` as `T` no matter if that is valid or not, and without doing any additional instructions that might probably be needed to make it valid. – t.niese Aug 07 '20 at 17:36
  • Please try to explain your situation in words, not code. (The code can serve as illustration and clarification, but should not be the primary explanation.) Not only would your question be more accessible to more people, but taking the time to write out what you mean often benefits your own understanding. – JaMiT Aug 07 '20 at 17:38
  • Alternative to `IScenarioStep` that I like because I'm not a fan of Hungarian, maybe you'll like it too (or not). `namespace interface { struct ScenarioStep {...} }` – Eljay Aug 07 '20 at 17:45
  • @Eljay I did use it previously. Yes, it is fun to read, but once you try to get around fast with IDE/type it, that gets extremely tiring :) – Black Aug 09 '20 at 11:49

1 Answers1

9

reinterpret_cast should never be used to cast down the class hierarchy because it doesn't do base pointer adjustment, which is going to bite really hard in case of multiple inheritance.

One can (and should!) use static_cast if they can be certain true object type matches the one expected through some means. static_cast would still be 0-cost when base pointer adjustments are not needed, and will work correctly when they are required (albeit at a cost).

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Thank you for your quick answer! Does it make `static_cast` compilation only cost? Or the adjustments will go into runtime? – Black Aug 07 '20 at 17:31
  • 2
    static_cast will have run-time costs (pointer adjustment) if the hierarchy requires it, reinterpret_cast will not perform the adjustment even if it is needed. The benefit dynamic_cast provides is that it will fail if the cast is not proper for the given object/type combination. – SoronelHaetir Aug 07 '20 at 17:37
  • 1
    @Black The possible runtime costs associated with `static_cast` will be a single `add` or `sub` instruction by a constant. That's effectively free. – Justin Aug 07 '20 at 17:52
  • 1
    @Black • unless/until multiple virtual inheritance is involved, in which case it can get have a little more overhead (but only if needed). Using the wrong cast to avoid that extra necessary overhead will lead to future bugs *job security*. – Eljay Aug 07 '20 at 18:07
  • 1
    @Black i believe, your questions are answered, let me know if they are not. – SergeyA Aug 07 '20 at 18:09
  • I dunno, Eljay. Current trend is toward keeping maintenance costs down. If you write crap confusing code for job security, you might wind up being the cost cut. – user4581301 Aug 07 '20 at 18:10
  • @Black Fast code that doesn't work is useless. Write good code. Test it. If you need extra speed to meet the requirements, profile it to find out where you should make changes and then start making choices about what you're willing to complicate or take risks on for greater speed. – user4581301 Aug 07 '20 at 18:13
  • @user4581301 when I write code that I want to learn ways of c++ with, I do not look for working ;p I look for understanding :) Thank you all, It is all clear to me, and my _job security_ is pretty _secure_, as I do such an research before (like in this case). – Black Aug 07 '20 at 18:48