2013-07-17 3 views
1

У меня есть динамический бросок при компиляции g ++ (Redhat 5.5 gcc версии 3.4.6), который отлично работает на компиляторе Windows Visual Studio 2003, 2005 и 2010. Чтобы понять, что я вижу, я постараюсь быстро сломать проблему. У нас есть процесс, который загружается в множество «плагинов» из каталога и динамически загружает эти плагины (которые являются динамически связанными библиотеками). Предполагается, что этот процесс должен сравнить разные правила и типы данных, чтобы вернуть ответ. Чтобы сделать модульный процесс, мы поняли процесс «BaseDataType», но не о конкретных конкретных типах (чтобы мы могли поддерживать общий процесс). Поток программы выглядит примерно так:Dynamic Cast C++ Fail

Все наши типы «SpecifcObject» наследуют от «BaseDataType» как этот

class SpecificObject : public virtual BaseDataType { 

    ... Class Items ... 
} 

Это код из процесса выглядит следующим образом:

// Receive raw data 
void receive_data(void *buff, int size,DataTypeEnum type) 
{ 
    // Get the plugin associated with this data 
    ProcessPlugin *plugin = m_plugins[type]; 

    // Since we need to cast the data properly into its actual type and not its 
    // base data type we need the plugin to cast it for us (so we can keep the 
    // process generic) 
    BaseDataType *data = plugin->getDataObject(buff); 
    if(data) 
    { 
    // Cast worked just fine 
    .... Other things happen (but object isn't modified) .... 
    // Now compare our rule 
    RuleObject obj = getRule(); 
    ResultObject *result = plugin->CompareData(obj,data); 
    if(result) 
     ... Success Case ... 
    else 
     ... Error Case ... 
    } 
} 

Теперь это (обобщенно), что плагин будет выглядеть

BaseDataType* ProcessPluginOne::getDataObject(unsigned char *buff) 
{ 
    // SpecificObject inherits from BaseDataType using a "virtual" inheritance 
    SpecificObject *obj = reinterpret_cast<SpecificObject*>(buff); 
    if(obj) 
     return (BaseDataType*)obj; 
    else 
     return NULL; 
} 

ResultObject* ProcessPluginOne::CompareData(RuleObject rule, BaseDataType *data) 
{ 
    ResultObject *obj = NULL; 
    // This method checks out fine 
    if(data->GetSomeBaseMethod()) 
    { 
     // This cast below FAILS every time in gcc but passes in Visual Studio 
     SpecificObject *obj = dynamic_cast<SpecificObject*>(data); 
     if(obj) 
     { 
      ... Do Something ... 
     } 
    } 

    return result; 
} 

Опять все это работает под Visual Studio, но не под GCC. Чтобы отладить программу, я начал добавлять код в разные разделы. Я, наконец, получил его на работу, как только я сделал следующее в главном процессе (см добавлен код ниже):

// In process with Modification 
void receive_data(void *buff, int size,DataTypeEnum type) 
{ 
    // Get the plugin associated with this data 
    ProcessPlugin *plugin = m_plugins[type]; 

    // Since we need to cast the data properly into its actual type and not its 
    // base data type we need the plugin to cast it for us (so we can keep the 
    // process generic) 
    BaseDataType *data = plugin->getDataObject(buff); 
    if(data) 
    { 
    // Cast worked just fine 
    .... Other things happen (but object isn't modified) .... 
    // Now compare our rule 
    RuleObject obj = getRule(); 

    /** I included the specific data types in as headers for debugging and linked in 
     * all the specific classes and added the following code 
     */ 
    SpecificObject *test_obj = dynamic_cast<SpecificObject*>(data); 
    if(test_obj) 
     cout << "Our was Data was casted correctly!" << endl; 
    /// THE CODE ABOVE FIXES THE BAD CAST IN MY PLUGIN EVEN THOUGH 
    /// THE CODE ABOVE IS ALL I DO 


    ResultObject *result = plugin->CompareData(obj,data); 
    if(result) 
     ... Success Case ... 
    else 
     ... Error Case ... 
    } 
} 

Существенная процесса компилирования Опции:

Compile: -m64 -fPIC -wno-non-template-friend -DNDEGBUG -I <Includes> 
Link: -Wl -z muldefs -m64 

Существенная Plugin Compile Options

Compile: -Wall -wno-non-template-friend -O -O2 
Link: -Wl -Bstatic -Bdynamic -z muldefs -shared -m64 

Поскольку я не изменяю объект «данные», я понятия не имею, почему остальная часть программы внезапно начнет работать. Единственное, что я могу придумать, это то, что виртуальная таблица отделяется где-то в этом процессе, а «дополнительный» динамический бросок заставляет основной процесс хранить таблицу (что по-прежнему не имеет большого смысла).

Я попытался вынести все настройки оптимизации в gcc и его все еще то же самое. Любые мысли о том, что здесь происходит?

Спасибо.

+0

Что такое * фактический * код и код вызова для 'getDataObject'? Как вы уже опубликовали, код не может скомпилировать (' void * 'автоматически не присваивается' unsigned char * ') –

+0

Извините ... Его фактически просто неподписанный char * not void * Это была опечатка. Я подтвердил, что внутри getDataObject интерпретация реинтерпрета работает просто отлично и, похоже, является допустимым SpecificObject. Код _actual_ внутри getDataObject выглядит точно как отправлено (минус void * typo). – Nashirak

+0

GCC 3.4.6 - очень древняя версия GCC (2004). Текущая версия - 4.8.1, она работает лучше (лучшая диагностика, лучшая оптимизация, лучшее стандартное соответствие). ** Пожалуйста, обновите свой компилятор GCC ** –

ответ

1

двух наиболее вероятных сценариев, которые BaseDataType не является полиморфным типом, или, что компилятор не видит взаимосвязи между BaseDataType и SpecificObject в какой-то момент в коде (например, в getDataObject компилятор может генерировать различный код в зависимости от знания отношений родитель-ребенок, поскольку вы используете C-cast от ребенка к родительскому. Это очень легко проверить: измените C-cast на static_cast. Если он не скомпилирован, вам не хватает критически важного значения.

+0

Поскольку мы используем BaseDataType в других областях и не испытывали никаких проблем (просто не этот точный поток). Я могу сказать, что BaseDataType является полиморфным. Я попробовал static_cast, и он скомпилирован просто отлично. Я убежден, что я либо компилирую что-то неправильно (отсутствует опция или плохое сочетание опций), либо (маловероятно, но возможно) есть ошибка компилятора в этой версии gcc. – Nashirak