Expensive dynamic cast

Дорогой dynamic_cast используется вместо более эффективного static_cast или const_cast

Описание

Этот дефект повышен когда dynamic_cast используется на указателе, который затем сразу разыменовывается. Например:

std::iostream* iostream_ptr;
//...
std::string str = dynamic_cast< std::stringstream* >( iostream_ptr )->str();
iostream указатель iosreeam_ptr брошен в stringstream указатель, и затем сразу разыменованный. Такое использование подразумевает, что кастинг всегда успешно выполняется. Когда вы знаете, что операция кастинга успешно выполняется, static_cast или const_cast более эффективный выбор.

Риск

При кастинге одного класса другому в полиморфной иерархии вы можете хотеть использовать dynamic_cast когда тип выполнения большей части производного класса в иерархии неизвестен. dynamic_cast более мощно, потому что это проверяет тип аргумента во время выполнения и сообщает об ошибке, если проверка перестала работать. Это дополнительные функциональности делает dynamic_cast более дорогая операция, чем любой из static_cast или const_cast. Поскольку dynamic_cast универсально, его использование может сделать код более трудным понять. Используя dynamic_cast когда более дешевые или более явные операции кастинга могут быть более соответствующими результатами в коде, который является неэффективным и более трудным обеспечить. Поскольку такой код скомпилировал и запустил правильно, неэффективность может остаться необнаруженной.

Исправление

Чтобы зафиксировать этот дефект, замените dynamic_cast с более соответствующей более дешевой опцией. Например:

  • При вызывании виртуальных функций в полиморфном базовом классе удалите любую операцию кастинга.

  • Когда downcasting от базового класса до производного класса, используйте static_cast если операция кастинга преуспевает во всех условиях.

  • Когда sidecasting от одного базового класса до другого базового класса, используйте static_cast если операция кастинга преуспевает во всех условиях.

  • Когда upcasting от производного класса до базового класса, используйте static_cast.

  • Изменить const или volatile спецификаторы объекта, используйте const_cast.

  • Осуществите рефакторинг свой код, чтобы удалить несоответствующий кастинг, такой как кастинг между несвязанными классами.

Повышения производительности могут варьироваться на основе компилятора, реализации библиотеки и среды, которую вы используете.

Примеры

развернуть все

#include <cstddef> 
#include <sstream> 
#include <string>
// downcast using `dynamic_cast` with pointer,
// and unconditionally call member function
void Downcast_NC( std::iostream* iostream_ptr )
{
	// ...
	std::string str = dynamic_cast< std::stringstream* >( iostream_ptr )->str(); //Noncompliant
	// ...
}

В этом примере, std::iostream* объект брошен в std::stringstream* объект путем вызова dynamic_cast. После кастинга сразу разыменовывается указатель броска. Polyspace® отмечает dynamic_cast.

Коррекция

Чтобы зафиксировать этот дефект, замените dynamic_cast при помощи static_cast. Поскольку static_cast не проверяет, может ли операция кастинга привести к сбою, рассмотреть добавление assert оператор, чтобы проверять, перестало ли преобразование работать. После завершения разработки и отладки, вы можете удалить assert оператор.

#include <cstddef> 
#include <sstream> 
#include <string>
void Downcast_C( std::iostream* iostream_ptr ) 
// if `dynamic_cast` may fail
{
	// ...
	assert( dynamic_cast< std::stringstream* >( iostream_ptr ) != NULL );//Only for debugging
	std::string str = static_cast< std::stringstream* >( iostream_ptr )->str(); //Compliant
	// ...
}
class A{
	//...
public:
	virtual void func_A() ;
};
class B{
	//...
public:
	virtual void func_B() ;
};
class C: public A, public B{/**/};	
void foo(A& a){
	
	dynamic_cast<B*> (&a)->func_B();//Noncompliant
}
void bar(C& c){
	
	dynamic_cast<B*> (&c)->func_B();//Noncompliant
}

В этом примере, класс C выведен из A и B. Функциональный foo бросает A& объект a в B* введите, чтобы получить доступ к функции членства B::func_B. Операция кастинга вызывает dynamic_cast, который неэффективен. Polyspace отмечает это преобразование.

Кастинг от C& возразите против его базового класса, как показано в функциональном bar, всегда успешно выполняется. Используя dynamic_cast поскольку эта операция является ненужной, и Polyspace отмечает преобразование.

Коррекция

Sidecasting через неизвестное большая часть производного класса является уникальной возможностью dynamic_cast. Если ваш код не может функционировать правильно без sidecast, используйте dynamic_cast и выровняйте по ширине дефект. Смотрите Аннотируют Код и Скрывают Известные или Приемлемые результаты.

В некоторых случаях может быть более эффективно заменить sidecast на удрученное. Например, функциональный foo использование sidecasting для явной цели получить доступ к членам другой ветви в иерархии классов. В таких случаях может быть более эффективно выполнить кастинг через большую часть производного класса. Вместо того, чтобы использовать dynamic_cast бросать a в B* объект, вы можете использовать static_cast бросать a в C* объект. Такое удрученное включает доступ к B::func_B при создании кода более эффективным. Чтобы проверять, преуспевает ли статическое преобразование во всех условиях, используйте assert операторы во время разработки и отладки.

Upcasting от производного класса до базового класса, как показано в функциональном bar, всегда успешно выполняется. Используйте static_cast для таких преобразований. В предыдущем коде, потому что func_B общедоступная виртуальная функция, вызовите функцию непосредственно при помощи указателя на класс C. Кастинг не необходим в этом случае.

class A{
	//...
public:
	virtual void func_A() ;
};
class B{
	//...
public:
	virtual void func_B() ;
};
class C: public A, public B{/**/};	
void foo(A& a){
	
	static_cast<C*> (&a)->func_B();//Compliant
}
void bar(C& c){
	
	c.func_B();//Compliant
}

Информация о результате

Группа: Производительность
Язык: C++
Значение по умолчанию: Off
Синтаксис командной строки: EXPENSIVE_DYNAMIC_CAST
Удар: Средняя
Введенный в R2021b