Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and why is an std::__non_rtti_object exception generated?

I'm using Visual Studio and performing a valid dynamic cast. RTTI is enabled.

Edit : Updated the code to be more realistic

struct base
{
    virtual base* Clone()
    {
        base* ptr = new base;
        CopyValuesTo( ptr );
        return ptr;
    }
    virtual void CopyValuesTo( base* ptr )
    {
       ...
    }
    virtual ~base()
    {
    }
}

struct derived : public base
{
    virtual base* Clone()
    {
        derived* ptr = new derived;
        CopyValuesTo( ptr );
        return ptr;
    }
    virtual void CopyValuesTo( base* ptr )
    {
       ...
    }
    virtual ~derived()
    {
    }
}  

void Class1::UseNewSpec( base* in_ptr ) //part of a totally unrelated class
{
    derived* ptr = dynamic_cast<derived *>(in_ptr);
    if( !ptr )
       return;
    delete m_ptr;
    m_ptr = ptr->Clone(); //m_ptr is a member of Class1 of type base*
}

//usage : 
Class1 obj;
derived new_spec; 
obj.UseNewSpec( &new_spec );

My debugger says that in_ptr is of the correct type when the exception is thrown. Google seems particularly unhelpful. Any ideas? Cheers.

like image 777
Carl Avatar asked May 12 '09 21:05

Carl


3 Answers

https://learn.microsoft.com/en-us/cpp/cpp/typeid-operator?view=vs-2019 has info on __non_rtti_object_exception.

From MSDN:

If the pointer does not point to a valid object, a __non_rtti_objectexception is thrown, indicating an attempt to analyze the RTTI that triggered a fault (like access violation), because the object is somehow invalid (bad pointer or the code wasn't compiled with /GR).

like image 54
Michael Avatar answered Oct 11 '22 06:10

Michael


RTTI exceptions, failures, or errors around a dynamic_cast can mean that you performed an illegal cast. dynamic_cast<derived*>(ptrToBase) is valid if and only if class derived and class base both meet the following constraint: that class, or one of its base classes, has a virtual member function.

This virtual member function can be anything, including the destructor. If you don't have any other member functions, you can try:

struct base
{
    virtual ~base(){}
    ...
}

struct derived : public base
{
    ...
}

Now base has a virtual member function, and so does derived. Try that out and see if it resolves your issue.

EDIT-ADD:

@carleeto -- In "it already had a virtual destructor", doe it==base?

If derived has virtual destructor but base is non-virtual dtor, then you may still get this error.

Also, you should verify that the object hasn't been destructed -- once the destructor runs, dynamic_cast is no longer safe to call. Try adding a trace to the ctors and dtors.

like image 33
Aaron Avatar answered Oct 11 '22 05:10

Aaron


I ran a test based on your pseudo-code and it works. So if RTTI is truly enabled in your build configuration, then it must be another problem that isn't captured in what you posted.

like image 6
Skrymsli Avatar answered Oct 11 '22 04:10

Skrymsli