2010-09-17 2 views
1

у меня есть следующие иерархии классов:C++ Виртуальный деструктор Краш

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

Non из указателей являются NULL, и void* ptrIS MoreDerived * (или, по крайней мере, Base *), но приложение по-прежнему падает ...

+0

Ваш пример кода кажется неполным - «static_cast (PTR)» не является законным, оно нуждается в тип, указанный (что-то вроде static_cast (PTR)), и вы, вероятно, следует использовать reinterpret_cast так или иначе. Вы также используете конструктор для MoreDerived, который вы нигде не объявляете/не определяете. Не могли бы вы отредактировать свой пост, чтобы код лучше отражал ваш реальный код? –

+0

Почему вы думаете, что вам нужно отбросить его на 'void *'? –

+0

платформа? компилятор? – pm100

ответ

1

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

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

2

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

2

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

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

+0

указатель - указатель. Знания компиляторов находятся в таблице vtable того, на что она указывает; когда он отбрасывает его, все должно быть хорошо – pm100

+0

+1 Предупреждение Марка новичкам выглядит глубоко правдивым. –

+0

@ pm100, это сложнее, чем это. http://en.wikipedia.org/wiki/Virtual_method_table#Multiple_inheritance_and_thunks –

3

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

+0

Я полагаю, делая Base* ptrToBase = obj;, я уже сделал static_cast до Base* ?? – MaaTt

+0

Я обновил сообщение для ответа. Я полагаю, делая Base* ptrToBase = obj;, я уже сделал static_cast до Base* ?? – MaaTt

2

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

0

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

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

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 Billy O'Neal: Я полагаю, делая Base* ptrToBase = obj;, я уже сделал static_cast до Base* ??

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

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

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

+0

Почему вы хотите удалить объект в отдельный поток ??? – Tomek