#c #rtti #dynamic-cast
#c #rtti #динамическое приведение
Вопрос:
Мне любопытно узнать, что происходит при компиляции кода с динамическим приведением с отключенным RTTI (либо с -fno-rtti
помощью GCC, либо с /GR-
помощью Visual Studio). Компилятор «возвращается» к static_cast
? Поскольку (по крайней мере, в VS) он выдает только предупреждение, что будет делать скомпилированный код?
Более конкретно, какие плохие вещи могут произойти, если я скомпилирую без RTTI код, в котором я уверен, что с dynamic_cast не может быть ошибок (т. Е. Где dynamic_cast
можно было бы безопасно заменить на static_cast
), подобных этому :
class A{ /*...*/ } ;
class B : public A {
int foo() { return 42 ;}
} ;
//...
A * myA = new B() ;
int bar = (dynamic_cast<B*>(myA))->foo() ;
Комментарии:
1. Почему бы просто не попробовать?
2. Почему ваш код использует,
dynamic_cast
если вы уверены, что этоstatic_cast
можно использовать вместо этого?3. @edA-qamort-ora-y: Я знаю, что это лучше (и на самом деле это то, что я сделал с оскорбительным кодом), я просто хотел знать, что произойдет
4. @EranZimmerman : Я выяснил, что был выброшен объект std::__non_rtti_, но только в некоторых случаях (я до сих пор не знаю, почему)
5. @EranZimmerman Хотелось бы знать, всегда ли это будет работать на любой платформе и компиляторе, а не готовить тикающую бомбу, готовую взорваться при переключении компилятора.
Ответ №1:
Читая стандарт, в 5.2.7 / 6 мы обнаруживаем, что, если целевой объект не является однозначной базой источника, источник должен быть полиморфного типа. Затем в 10.3 / 1
Виртуальные функции поддерживают динамическое связывание и объектно-ориентированное программирование. Класс, который объявляет или наследует виртуальную функцию, называется полиморфным классом.
Другими словами, стандарт, похоже, ничего не говорит о вашем вопросе. В этом случае стандарт не позволяет компилятору отключать RTTI, поэтому для каждого компилятора вам нужно проверить его документацию, чтобы увидеть, что произойдет. Основываясь на этом чтении, я думаю, что это вопрос компилятора, а не вопрос языка C , как указывает тег.
С другой стороны, вы можете полностью избежать проблемы, просто используя static_cast
, когда вы знаете, что этого достаточно.
Ответ №2:
В MSVC, если ваш код не скомпилирован с включенным RTTI, будет выдано __non_rtti_object
исключение, если приведение не может быть выполнено без проверки во время выполнения.
Ответ №3:
Самый простой способ узнать это — попробовать.
Вы обнаружите, что некоторые из ваших динамических приведений будут помечены как незаконные. Некоторые не будут. Например, преобразование известно во время компиляции, когда вы используете динамическое приведение для преобразования в однозначный базовый класс.
Добавление
Повторно «Поскольку (по крайней мере, в VS) он выдает только предупреждение …» Игнорируйте предупреждения на свой страх и риск. Лучшее, что нужно сделать, это убедиться, что ваш код компилируется без предупреждений, с очень высокими уровнями предупреждения (и, возможно, преобразованными в ошибки). Во-вторых, лучше всего просмотреть каждое получаемое вами предупреждение и убедиться, что ничего плохого не происходит. В этом случае произойдет что-то нежелательное. Вас действительно не должно волновать, как реализуется это нежелательное событие. О чем вам следует позаботиться, так это избавиться от него.
Комментарии:
1. Я знаю, что обычно лучше удалить причину предупреждения, чем жить с этим. Что я имел в виду под «он выдает только предупреждение», так это то, что компилятор все еще принял (но не одобрил) код и скомпилировал его во что-то.
2. Что это за «что-то», зависит от реализации. Стандарт является спорным, когда дело доходит до отключения RTTI.
Ответ №4:
Просто попробуйте:
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <memory>
#include <vector>
#include <array>
#include <string>
class Base {
public:
virtual ~Base() {
}
};
class A: public Base {
};
class B: public Base {
};
using namespace std;
int main() {
A *a = new A;
auto *ptr = dynamic_cast<B*>(a);
if (!ptr)
std::cout << "failed to cast" << std::endl;
return 0;
}
Без -fno-rtti
программа компилируется, и результат является:
failed to cast
С -fno-rtti
не удалось скомпилировать программу:
main.cpp:25:35: error: ‘dynamic_cast’ not permitted with -fno-rtti
auto* ptr = dynamic_cast<B*>(a);
^
Вы также можете протестировать это онлайн здесь:https://onlinegdb.com/pYTQu2ne2
Комментарии:
1. Проблема с выводом правил по поведению компилятора вы можете столкнуться с ошибкой компилятора и полагаться на неправильные правила.