Expensive logical operation

Логическая операция требует оценки обоих операндов из-за их порядка, приводящего к неэффективному коду

Описание

Этот дефект происходит, когда все эти условия верны:

  • Левые и правые операнды не имеют никаких побочных эффектов.

  • Правильный операнд не содержит вызовов const функции членства.

  • Левый операнд содержит один или несколько вызовов const функции членства.

При оценке возможных побочных эффектов операнда:

  • Polyspace® принимает тот const функции членства класса не имеют побочных эффектов. Функции лица, не являющегося членом какой-либо организации, приняты, чтобы иметь побочные эффекты.

  • Polyspace обрабатывает операции с плавающей точкой в соответствии со стандартом C++. На C++ 03 или более ранние, операции с плавающей точкой не имеют никаких побочных эффектов. В C+11 или позже, операции с плавающей точкой могут иметь побочные эффекты, такие как изменение флагов состояния с плавающей точкой, чтобы указать на аварийные результаты или вспомогательную информацию. Смотрите среду С плавающей точкой.

  • Polyspace обрабатывает bool оператор преобразования и логический NOT операторы struct или класс как встроенные операторы. Эти операции не обработаны как вызовы функции членства. Стандартная библиотека шаблонов содержит много классов, которые задают такой bool оператор преобразования или логический NOT оператор.

Риск

При оценке логической операции компилятор оценивает левый аргумент сначала, и затем оценивает правильный аргумент только при необходимости. В логической операции это неэффективно, чтобы поместить вызовы функции в качестве левого аргумента при помещении постоянный и переменные в качестве правильного аргумента. Рассмотрите этот код:

if(Object.attribute()|| var1){
//...
}
В логическом выражении в if оператор, компилятор всегда оценивает вызов функции Object.attribute(). Выполнение функции не всегда необходимо. Например, если var1 оценивает к true, затем логическое выражение всегда оценивает к истине. Поскольку var1 правильный операнд, не левый операнд, компилятор излишне оценивает вызов функции, который неэффективен. Поскольку неэффективный код компилирует и ведет себя правильно, эта дефектная сила остаются незамеченными.

Фиксация

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

Если это условие не верно, то код использует точный порядок, в котором компилятор выполняет отмеченное логическое выражение. Лучшая практика не состоит в том, чтобы использовать порядок оценки выражения. Рассмотрите рефакторинг вашего кода так, чтобы порядок оценки не оказывал влияния. Если рефакторинг кода не возможен, выровняйте по ширине дефект при помощи аннотации или рассмотрите информацию. Смотрите Результаты Polyspace Адреса Через Исправления ошибок или Выравнивания.

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

Примеры

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

#include <string>
bool updateNewProperty( const std::string& name );
void updateNewMetaProperty( const std::string& name );
volatile char externalFlag;

void updateProperty( const std::string& name )
{
	bool is_new_property = updateNewProperty( name );

	if( name.compare( "meta" ) == 0 && is_new_property ) //Noncompliant
	{
		updateNewMetaProperty( name );
	}
	if( name.compare( "meta" ) == 0 && externalFlag ) //Compliant
	{
		updateNewMetaProperty( name );
	}
	
}

В первом if оператор, переменная is_new_property правильный операнд логического операнда. Функция членства std::string::compare называется в качестве левого аргумента. Компилятор оценивает вызов функции независимо от значения is_new_property, который неэффективен. Polyspace отмечает логическую операцию.

Во втором if оператор, volatile переменная externalFlag правильный операнд. Поскольку переменной является volatile, Polyspace принимает, что может вызвать побочный эффект. Поскольку volatile переменная сила имеет побочный эффект, Polyspace не отмечает логическую операцию.

Коррекция

Определите, должен ли порядок операндов быть поддержан, чтобы выполнить выражение безопасно и правильно. В этом случае, эти два операнда is_new_property и name.compare( "meta" ) == 0 независимы и изменяются, их порядок не изменяет значение логического выражения. Чтобы зафиксировать этот дефект, используйте is_new_property как левый операнд.

#include <string>
bool updateNewProperty( const std::string& name );
void updateNewMetaProperty( const std::string& name );
volatile char externalFlag;

void updateProperty( const std::string& name )
{
	bool is_new_property = updateNewProperty( name );
	if(is_new_property && name.compare( "meta" ) == 0 ) //Compliant
	{
		updateNewMetaProperty( name );
	}
	if( name.compare( "meta" ) == 0 && externalFlag ) //Compliant
	{
		updateNewMetaProperty( name );
	}
}

Компилятор оценивает вызов std::string::compare в первом if оператор только, когда is_new_property true.

Когда вы используете операции с плавающей точкой в логическом выражении, Polyspace оценивает побочные эффекты операндов по-другому на основе версии C++, который вы используете. На C++ 03 или более ранние версии, операции с плавающей точкой не имеют никаких побочных эффектов собой. На C++ 11 или позже, сами операции с плавающей точкой могут иметь побочные эффекты.

class A{
	//...
	float makeFloat() const{
		//..
	}
	void testfloat(){
		if( makeFloat() == 0.1f && fp==0.2f) //Noncompliant
		{
			//...
		}
	}
	
private:
	float fp;		
};
В этом коде, если вы используете C++ 03, ни один из операндов не имеет побочные эффекты. Поскольку левый операнд вызывает вызов функции членства, Polyspace отмечает выражение.

Если вы используете C++ 11 или позже, операции с плавающей точкой могут иметь побочные эффекты. В этом случае Polyspace не отмечает логическое выражение.

Коррекция

Определите, должен ли порядок операндов быть поддержан, чтобы выполнить выражение безопасно и правильно. В этом случае, эти два операнда fp==0.2f и makeFloat() == 0.1f независимы и изменяются, их порядок не изменяет значение логического выражения. Чтобы зафиксировать этот дефект, используйте fp==0.2f как левый операнд.

class A{
	//...
	float makeFloat() const{
		//..
	}
	void testfloat(){
		if( fp==0.2f && makeFloat() == 0.1f) //Compliant
		{
			//...
		}
	}
	
private:
	float fp;		
};
Компилятор оценивает вызов makeFloat() только, когда fp==0.2f оценивает к true.

#include<cstdlib>
class A{
	//...
	bool isLoaded() const { return p != NULL; }
	int get() {
		if(isLoaded() && *p > 0) { // Noncompliant
			return *p;
		}
	}

	
private:
	int* p;		
};

В выражении (isLoaded() && *p > 0), разыменование *p в правильном аргументе безопасно только, когда левым аргументом является true. Polyspace не проверяет, когда логическое выражение требует такого определенного порядка оценки. Поскольку никакой операнды имеют побочные эффекты, и вызов функции членства является левым операндом, Polyspace отмечает операцию.

Коррекция

В этом случае, порядок, если операнды в логическом выражении должен быть обеспечен, чтобы выполнить выражение безопасно и правильно. Чтобы зафиксировать этот дефект, осуществите рефакторинг свой код. Лучшая практика не состоит в том, чтобы использовать порядок оценки выражения.

#include<cstdlib>
class A{
	//...
	bool isLoaded() const { return p != NULL; }
	int get() {
		if(isLoaded()== true) { // Compliant
			if(*p > 0){
				return *p;	
			}
			
		}
	}

	
private:
	int* p;		
};
Этот код проверяет эти два условия отдельно и не использует порядок оценки. Если такой рефакторинг не выполним, выровняйте по ширине дефект при помощи аннотаций или рассмотрите информацию.

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

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