Expensive constant std::string construction

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

Описание

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

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

  • The 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 времени. Каждый временной foo вызывается, s1, s2, и 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();
}
The std::string s3 объекта объявлен как static. Потому что s3 является static, он построен только один раз, даже если foo называется 10000 времени. The 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 объекты s1, s2, s5, и s6 потому что, если эти строки строятся из постоянных данных каждый раз foo называется, но остается неизмененным после конструкции.

  • Флаги Polyspace s4 и 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