Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

By accident I found that with a polymorphic type using dynamic_cast back to the derived class will throw a 'bad cast' error if the pointer is no longer valid. Is this undefined behavior or could this be a way to check for valid pointers without using smart pointers?

I'm not really against using smart pointers as they serve a real need, but I dislike the syntax. I don't have anything against templated types but I find smart pointers to bloat the code and I'm not a fan of macro's to try and avoid that bloat. I wish C++ included something in the language syntax itself vs using the template feature but with this question I'm more concerned about what is happening below and if this is a valid and defined way to checking for valid pointers as this gives an exception every time from my tests.

#include <string>
#include <map>


using namespace std;

class Base
{
public:
    virtual ~Base(){}
};

class Derived : public Base
{
public:
    virtual ~Derived(){}
};

class Storage
{
private:
    map<string, Base*> storage;
public:
    void AddItem(string name, Base* base)
    {
        if (storage.find(name) == storage.end())
        {
            storage[name] = base;
        }
    }

    template <class T>
    T& FindItem(string name)
    {
        if (storage.find(name) != storage.end())
        {
            Base* item = storage[name];

            return dynamic_cast<T&>(*item);
        }

        throw;
    }
};

int main()
{
    Storage store;

    // force 'd' to go out of scope for our test
    {
        Derived d;

        store.AddItem("test", &d);
    }

    // this will throw a bad cast exception
    Derived& test = store.FindItem<Derived>("test");


    return 0;
}
share|improve this question

2 Answers 2

up vote 10 down vote accepted

dynamic-cast needs to deference the pointer to find the proper offset it should be at, dereferencing an invalid pointer is undefined behavior,

one thing you might see:

class Derived2 : public Base
{
public:
    virtual ~Derived2(){}
};

int main()
{
    Storage store;

    {
        Derived d;

        store.AddItem("test", &d);
    }

    {
        Derived2 d2;

        Derived2& test = store.FindItem<Derived2>("test");//might not throw an exception
        //test might refer to d2
    }


    return 0;
}

Messing about with a void* buffer and placement new and destroy will let me insert anything in there.

Just go with smart pointers and learn to appreciate them for the blessing that they are.

share|improve this answer
    
I'm confused as to why test might refer to d2 in your example? Is it because it might have taken the memory location of the original d since it was created after d went out of scope and could have used the same memory that d did when it was valid? –  user441521 May 19 at 14:23
    
@user441521 yes, exactly –  ratchet freak May 19 at 14:24
1  
Thanks for the explanation and example. I don't think I'll ever enjoy the smart pointer syntax as it is, but I'll just use them for the problems they solve. This makes sense to me now. –  user441521 May 19 at 14:28

This is, indeed, undefined behaviour.

dynamic_cast needs to look up the run-time type for your pointer, which will generally require dereferencing it, and this is already UB.

Even if an implementation somehow avoid dereferencing the pointer - say by storing a lookup table with the type of each live object, indexed by address range - the fact that your object went out of scope means the same address could be reused by some other object. So, even in this (very contrived) scenario, you wouldn't necessarily get the result you want.

The only answer is to manage lifetimes correctly. As ratchet freak says, smart pointers are probably your best bet here.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.