Когда и почему генерируется исключение std :: __ non_rtti_object? - PullRequest
4 голосов
/ 13 мая 2009

Я использую Visual Studio и выполняю правильное динамическое приведение. RTTI включен.

Редактировать: обновлен код, чтобы он стал более реалистичным

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 );

Мой отладчик говорит, что in_ptr имеет правильный тип, когда выдается исключение. Google кажется особенно бесполезным. Есть идеи? Приветствия.

Ответы [ 5 ]

8 голосов
/ 13 мая 2009

http://msdn.microsoft.com/en-us/library/fyf39xec(VS.80).aspx содержит информацию о __non_rtti_object_exception.

Из MSDN:

Если указатель не указывает на действительный объект, __non_rtti_objectexception бросается, указывая попытаться проанализировать RTTI, что вызвал ошибку (например, доступ нарушение), потому что объект как-то неверно (плохой указатель или код не был скомпилирован с /GR).

5 голосов
/ 13 мая 2009

Я запустил тест на основе вашего псевдокода, и он работает. Так что, если RTTI действительно включен в вашей конфигурации сборки, то это должно быть еще одна проблема, которая не отражена в ваших публикациях.

5 голосов
/ 13 мая 2009

Исключения RTTI, сбои или ошибки вокруг dynamic_cast могут означать, что вы выполнили недопустимое приведение. dynamic_cast<derived*>(ptrToBase) допустимо, если и только если класс derived и класс base оба соответствуют следующему ограничению: этот класс или один из его базовых классов имеет функцию виртуального члена.

Эта виртуальная функция-член может быть чем угодно, включая деструктор. Если у вас нет других функций-членов, вы можете попробовать:

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

struct derived : public base
{
    ...
}

Теперь base имеет функцию виртуального члена, как и производную. Попробуйте это и посмотрите, решит ли это вашу проблему.

EDIT-ADD:

@ carleeto - в "у него уже был виртуальный деструктор", да == base?

Если производный имеет виртуальный деструктор, но база не является виртуальным dtor, вы все равно можете получить эту ошибку.

Кроме того, вы должны убедиться, что объект не был разрушен - после запуска деструктора dynamic_cast больше не является безопасным для вызова. Попробуйте добавить след в ctors и dtors.

1 голос
/ 13 мая 2009

Убедитесь, что у вас включен RTTI во всех исходных файлах.

В противном случае указатель недействителен.

0 голосов
/ 13 мая 2009

Содержит ли base какие-либо virtual методы? Это должно для того, чтобы dynamic_cast работал.

...