Expensive constant std::string construction

Объект постоянной строки создается форма постоянные данные, приводящие к неэффективному коду

Описание

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

  • Вы создаете std::string объект из постоянных данных, таких как строковый литерал или выход constexpr функция.

  • std::string объект остается постоянным или немодифицированным после конструкции.

Это средство проверки не отмечает переменные члена класса и строковые литералы, которые являются аргументами функции.

Риск

Рассмотрите std::string объекты в блоке кода, который содержит постоянные данные, которые остаются немодифицированными после конструкции. Каждый раз блок кода выполняется, новый std::string объект создается без изменения в его содержимом. Повторная конструкция такого std::string объект без модификации содержимого является неэффективным и трудным обнаружить. Рассмотрите этот код:

#include <string>
constexpr char* getStrPtr() { 
	return "abcd"; 
}
void foo(){
	std::string s1 = "abcd";
	std::string s2{"abcd"};
	std::string s3 = getStrPtr();                 
}
int main(){
//...
for(int i = 0; i<10000; ++i)
      foo();
}
В этом коде, функциональном foo называется 10000 \times. Каждый раз foo называется, s1S2 , и s3 создаются из того же литерала постоянной строки abcd, получившийся в неэффективном коде. Поскольку такой неэффективный и запутывающий код компилирует и функционирует правильно, неэффективная конструкция std::string объекты из постоянных данных не могут быть замечены.

Фиксация

Фиксация для этого дефекта зависит от надлежащего использования постоянных данных.

  • Можно хранить постоянные данные в static представьте объект в виде строки, если вам нужны функциональности std::string класс.

  • Можно использовать постоянные данные непосредственно в качестве временных литералов, если вы не должны снова использовать данные.

  • Можно хранить постоянные данные при помощи const символьный массив или std::string_view возразите, не ли вам нужны функциональности std::string класс. std::string_view поддерживается C++ 17 и позже.

Рассмотрите этот код:

constexpr char* getStrPtr() { 
	return "abcd"; 
}
void foo(){
	static  std::string s3 = getStrPtr();
	 std::string_view s3a{s3};                
}
int main(){
//...
for(int i = 0; i<10000; ++i)
      foo();
}
std::string объект s3 объявляется как static. Поскольку s3 static, это создается только однажды даже если foo называется 10000 \times. std::string_view объект s2 показывает содержимое s3 и старается не создавать std::string возразите каждый раз foo называется. При помощи std::string_view и static объекты, вы избегаете ненужной конструкции постоянного std::string объекты. Этот метод также разъясняет что объекты s3 и s3a представляйте те же данные.

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

Примеры

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

#include <string>
constexpr char* getStrPtr() { 
	return "abcd"; 
}
constexpr size_t FOUR(){
	return 4; 
}
size_t getCount();
void CallFunc(std::string s);
void foo(){
	std::string s1 = "abcd";
	std::string s2{"abcd"};
	std::string s3 = getStrPtr();  
	std::string s4("abcd", FOUR());
	std::string s5("abcd"), s6("abcd");
}

void bar(){
	std::string s3a("abcd", getCount());
	char *p = "abcd";
	std::string s_p = p;
	CallFunc("message");
}

В этом примере, нескольких const std::string объекты объявляются.

  • Polyspace® отмечает std::string объекты s1S2 , s5, и s6 потому что, если эти строки создаются из постоянных данных каждый раз foo называется, но остается немодифицированным после конструкции.

  • Polyspace flagss4 и s3 потому что они создаются из констант времени компиляции, таких как постоянный литеральный abcd и выход constexpr функция. Объект s3a не отмечается потому что выход getCount не постоянное время компиляции.

  • Polyspace не отмечает эти объекты, когда они создаются из постоянных данных:

    • Объект, который не является std::string, такой как *p.

    • Временные объекты, которые создаются как аргумент функции, такой как объект, содержащий строковый литерал message в аргументе CallFunc.

Коррекция

Можно зафиксировать этот дефект несколькими способами. Например:

  • Можно объявить std::string объекты как static. Когда объектом является static, компилятор не восстанавливает его в различных осциллографах. Когда вам нужны функциональности std::string класс, это объявление является хорошей фиксацией.

  • Можно хранить постоянные данные в символьном массиве или символьном указателе. Эти объекты являются менее дорогими по сравнению с std::string.

  • Можно объявить постоянные строки как std::string_view объекты. Эти объекты не содержат копию постоянных строк, которая делает эти объекты эффективными.

#include <string>
#include <string_view>
constexpr char* getStrPtr() { 
	return "abcd"; 
}
constexpr size_t FOUR(){
	return 4; 
}

void foo(){
	static std::string s1 = "abcd";
	std::string_view s2{s1};
	const char *p = getStrPtr();
	std::string s3 = p;
	static std::string s4("abcd", FOUR());
	std::string_view s5{s1}, s6{s4};
}

Проверки на s1 и s4 фиксируются путем объявления их как static. Проверки на s2, s5 и s6 фиксируются путем объявления их как std::string_view объекты. Проверка на s3 фиксируется, храня постоянные данные в символьном указателе.

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

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