By accident I found that with a polymorphic type using dynamic_cast back to the
ID: 658528 • Letter: B
Question
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;
}
Explanation / Answer
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.
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.