C++ Виртуальный разрушитель Crash

У меня есть следующая иерархия классов:

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

вместе с объектами

Base* base = new Base();
MoreDerived* obj = new MoreDerived(*base);  

Есть часть кода, где мне нужно удалить объект MoreDerived, используя поток, таким образом, сначала нужно привести его к void*. В ветке у меня есть

void KillObject(void* ptr)  
{  
    delete static_cast<Base*>(ptr);  
}  

Не указатели равны NULL, и void* ptr IS MoreDerived* (или, по крайней мере, Base*), но приложение по-прежнему падает

6 ответов

Решение

Я думаю, что вы думаете о dynamic_cast<void*> который получает указатель на наиболее производный объект.

Вам не нужно проходить через void* просто удалить объект полиморфного типа. Просто возьмите любой указатель и delete будь то Base* к MoreDerived объект или MoreDerived*, Там нет необходимости в Kill метод.

В C++ приведение часто приводит к изменению адреса указателя. Вы должны привести к Base * перед кастингом в void *или у вас неопределенное поведение. (Приведение в / из Void * в порядке, но при приведении обратно оно должно быть точно такого же типа на обоих концах)

Если вы используете static_cast для void *, то только стандарт гарантирует, что static_cast с исходным типом указателя будет работать правильно. Как упоминалось ранее, вам нужно либо dynamic_cast, либо сначала использовать static_cast для Base*, а затем void*. static_cast из void * в Base* должен работать правильно.

Приведя указатель к void * вы удаляете знания компилятора о том, как преобразовывать дерево наследования вверх и вниз. Это особенно проблема, когда существует множественное наследование, так как два указателя на один и тот же объект не обязательно будут иметь одинаковое значение!

Не делай этого.

Если KillObject всегда удаляет Base *зачем это нужно void *? + Изменить ptr быть Base * и избавиться от актеров. Тогда, если вещь передана в Base *, Derived *или MoreDerived *, это будет работать.

Большое вам спасибо за все ответы.

Просто чтобы прояснить ситуацию и более подробно остановиться на коде, я использую gcc 4.1.2 в CentOS, и он пропускает тип в static_cast, это ошибка форматирования Stackru, и у меня есть

void KillObject(void* ptr)
{
delete static_cast< Base* >(ptr);
};
// There is a reason for the following as this is a snipet and stuff gets passed around
Base* base = new Base();
MoreDerived* obj = new MoreDerived( * base );
Base* ptrToBase = obj;
// Use ptrToBase in code with no problems
// Delete object, illustrative only - have to cast to void* to pass to API
pthread_run( ... , KillObject , (void*)ptrToBase);

Re Билли О'Нил: я полагаю, делая Base* ptrToBase = obj;Я уже сделал static_cast для Base*??

Re Mark Ransom: распечатывая указатель и выполняя шаги, которые удаляет, я вижу, что указатель имеет один и тот же адрес на всем протяжении, и он падает на ~MoreDerived(),

Re Potatoswatter: я думаю, что в "Более эффективный C++" они упоминали, используя dynamic_cast< void* > но я не смог найти это предложение снова. Я попробую и дам вам знать результат.

еще раз спасибо

Другие вопросы по тегам