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* >
но я не смог найти это предложение снова. Я попробую и дам вам знать результат.
еще раз спасибо