dynamic_cast не работает за пределами модуля в clang

Я вижу очень странный сбой, очень похожий на проблему, описанную в dynamic_cast при сбое компилятора llvm clang: dynamic_cast возвращает nullptr, когда я пытаюсь преобразовать базовый тип в производный тип для объекта производного типа. Хотя в моем случае typeid на самом деле показывает тот же динамический тип.

Ниже приведена функция отладки, которую я использую для проверки типов во время выполнения. Он берет указатель SrcType* и пытается динамически привести его к указателю DstType*. Если преобразование завершается неудачно, т. е. возвращаемый указатель равен nullptr, выводится сообщение об ошибке. Макрос VERIFY() проверяет истинность условия:

template<typename DstType, typename SrcType>
void CheckDynamicType( SrcType *pSrcPtr )
{
    VERIFY(dynamic_cast<DstType*> (pSrcPtr) != nullptr, 
           "Dynamic type cast failed. Src typeid: \'", typeid(*pSrcPtr).name(), 
           "\' Dst typeid: \'", typeid(DstType).name(), '\'');
}

И вот вывод, который я получаю:

Dynamic type cast failed. Src typeid: 'N8Diligent15RefCountersImplE' Dst typeid: 'N8Diligent15RefCountersImplE'

Я использую компилятор clang из набора инструментов Android ndk r16. Я компилирую с флагом rtti. Тот же код отлично работает на gcc и msvc. Еще немного информации: код также отлично работает, если я соберу его со средой выполнения gnustl (я не уверен, как gnu stl работает с clang, но тем не менее).

ОБНОВИТЬ

Потратив еще несколько часов на изучение проблемы, я обнаружил, что dynamic_cast дает сбой, когда он используется для объекта, созданного в другом модуле. Из этого Использование clang++, -fvisibility=hidden и typeinfo и type-erasure и эти сообщения похоже, что dynamic_cast должно работать, если класс помечен __attribute__((visibility("default"))), так что typeid структуры из двух модулей будут объединены. Это, однако, тоже не помогает, и я все еще вижу проблему.


person Egor    schedule 16.11.2017    source источник
comment
Похоже, вызвано простой типографской ошибкой.   -  person Öö Tiib    schedule 16.11.2017
comment
опубликуйте минимально воспроизводимый пример, пожалуйста   -  person Massimiliano Janes    schedule 16.11.2017
comment
@RustyX, почему? насколько я могу судить, семантика CheckDynamicType состоит в том, чтобы пройти, если указатель равен нулю или динамическое приведение выполняется успешно...   -  person Massimiliano Janes    schedule 16.11.2017
comment
У меня работает с APP_PLATFORM=android-21, APP_STL=c++_static, APP_ABI=x86 на Mac. Указатель ожидается для печати одного и того же идентификатора типа, или это ожидаемое указание на ошибку компилятора?   -  person Alex Cohn    schedule 16.11.2017
comment
@RustyX извините за запутанное описание. VERIFY() макрос проверяет, истинно ли выражение, и в противном случае печатает отладочное сообщение (я обновил вопрос, чтобы прояснить это). @ Öö-Tiib, значит, это не опечатка. @RustyX Dynamic type cast failed печатается, если это действительно не удалось (т.е. dynamic_cast вернуло nullptr), но тогда typeid показывает тот же тип, что и является моей проблемой   -  person Egor    schedule 16.11.2017
comment
@Alex-Cohn, макрос выводит отладочное сообщение только в том случае, если выражение оценивается как false. Таким образом, смысл сообщения, которое он печатает, заключается в том, что dynamic_cast вернул nullptr, но typeid делает вывод, что динамические типы действительно совпадают, что для меня не имеет смысла.   -  person Egor    schedule 16.11.2017
comment
Я считаю, что вы можете сделать вывод, каким должен быть ожидаемый typeid. И если вы проверите ту же конфигурацию на своей стороне, это может стать шагом вперед.   -  person Alex Cohn    schedule 16.11.2017
comment
@ Alex-Cohn typeid, напечатанный макросом, является правильным и ожидаемым идентификатором типа. Итак, получается, что у меня есть SrcType и DstType, для которых typeid(SrcType).name() == typeid(DstType).name(), но dynamic_cast<DstType*>(pSrcPtr) == nullptr. Я использую самую последнюю версию ndk, но строю для armv7.   -  person Egor    schedule 16.11.2017
comment
Пожалуйста, попробуйте это. Я использовал эмулятор с API=24.   -  person Alex Cohn    schedule 16.11.2017
comment
@ Алекс-Кон, спасибо, что изучили это. Я обнаружил, что это не удается, потому что я использую dynamic_cast для объекта, созданного в другом модуле. Это оказалось известной проблемой, и это сообщение russellmcc.com /posts/2013-08-03-rtti.html#foot1 предполагает, что маркировка класса с помощью __attribute__((visibility("default"))) должна помочь, но я все еще вижу проблему.   -  person Egor    schedule 17.11.2017
comment
Вы используете c++_shared или статический?   -  person Alex Cohn    schedule 17.11.2017
comment
@ Alex-Cohn Я пробовал оба, но ни один не работает. Я понимаю проблему так, что компилятор генерирует две одинаковые структуры typeid в двух модулях, а затем сравнивает только указатели, которые отличаются. Это не связано со статической или динамической версией библиотеки времени выполнения. Пометка видимости класса по умолчанию тоже почему-то не помогает.   -  person Egor    schedule 17.11.2017
comment
Пожалуйста, проверьте github.com/android-ndk/ndk/issues/533#. issuecomment-335977747   -  person Alex Cohn    schedule 19.11.2017
comment
@ Алекс-Кон, спасибо за ссылку. Это выглядит точно так же, как проблема, которую я вижу.   -  person Egor    schedule 22.11.2017
comment
@AlexCohn: Вероятно, следует поднять это до ответа, чтобы он был более заметен.   -  person Dan Albert    schedule 29.11.2017


Ответы (1)


Если вы используете стандартный системный компилятор, вероятность того, что dynamic_cast компилятора не работает, равна нулю. Это проверено и широко используется во всем, начиная с системного программного обеспечения.

person Colin LeMahieu    schedule 16.11.2017