Unnecessary use of std::string::c_str() or equivalent string methods

Вместо std::string объект, строковая операция использует струну до, полученную из std::string функции включая std::string::c_str, std::string::data(), std::string::at(), или std::string::operator[], получившийся в неэффективном коде

Описание

Этот дефект происходит, когда строковая операция выполняется при помощи указателя струны до, полученного из строковых функций, таких как std::string::c_str, std::string::data(), std::string::at(), и std::string::operator[]. Например, это средство проверки повышено когда:

  • Новый std::string или std::wstring неявно или явным образом создается из струны до, полученной из строковой функции. Эта ситуация возникает когда функция, ожидая const ссылка на строку сталкивается с const char* вместо этого.

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

  • Определенный std::string функции членства вызываются при помощи струны до, полученной из строковой функции. Отмеченные функции включают replaceдобавление, assignСравнение, и find. Используя std::string возразите непосредственно, чтобы вызвать std::string функции членства более эффективны.

  • Пользовательская функция, которая перегружается, чтобы принять любой из const char* или const std::string аргументы вызываются при помощи указателя струны до. Более эффективно вызвать std::string перегрузка такой функции. Когда функция перегружается таким образом, вызывая const char* перегрузка от тела const std::string перегрузка при помощи указателя струны до не повышает дефект.

Риск

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

void set_prop1(const char* str);
void set_prop2(const std::string& str);
void foo( std::string& str){
	//...
	set_prop1(str.c_str()); // Necessary
	//...
	set_prop2(str.c_str()); // Inefficient	
}
Функциональный foo вызывает две различных функции. Поскольку функциональный set_prop1 требует струны до как входа, с помощью str.c_str функция необходима, чтобы сформировать вход к set_prop1. Функциональный set_prop2 берет std::string как вход. Вместо того, чтобы непосредственно использовать str как вход к set_prop2, str.c_str используется, возможно, как ошибка вставки копии. Компилятор неявно создает новый std::string объект, который идентичен str, при помощи выхода str.c_str. Построение нового std::string объект в этом случае является ненужным и неэффективным. Поскольку этот код компилирует и функционирует правильно, этот неэффективный код не может быть замечен.

Исправление

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

void set_prop1(const char* str);
void set_prop2(const std::string& str);
void foo( std::string& input){
	//...
	set_prop1(str.c_str()); // Necessary
	//...
	set_prop2(str); // Efficient	
}
Используя str вместо str.c_str как введено к set_prop2 делает код более эффективным и фиксирует дефект.

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

Примеры

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

#include <string>
#include <utility>

class A
{
public:
	A( char const* );
	char const* c_str() const;
};
void CppLibFuncA(const std::string&);
void CppLibFuncB(std::string &&);
void bar( A const& );
std::string make_string();
bool contains( std::string const& str1, std::string const& str2 )
{
	return str1.find( str2.data() ) == std::string::npos;
}

void foo(const std::string& s, std::string&& rs, A& other){
	CppLibFuncA( s.data() ); 
	CppLibFuncB( std::move( rs ).c_str() ); 
	CppLibFuncA( make_string().data() ); 
	bar( other.c_str() ); 
	if(contains(s,make_string())){
		//...
	}
	
}

В этом примере, Polyspace® отмечает неявную конструкцию string объект при помощи струны до, которая получена из string функция.

  • Функциональный CppLibFuncA берет const std::string& как введено. Когда функциональный CppLibFunc называется при помощи s.data(), компилятор не может передать ссылку на объект s к функции. Вместо этого компилятор неявно создает новый std::string объект от указателя струны до и передают новый объект функции, которая неэффективна. Polyspace отмечает вызов std::string::data.

  • Поскольку вызов CppLibFuncB при помощи выхода std::string::c_str также неявно создает новый str::string объект, Polyspace отмечает вызов std::string::c_str.

  • Вызов функционального bar не отмечается потому что const char* неявно не преобразован в новый std::string объект.

  • В функциональном contain, Polyspace отмечает вызов std::string::find(), где выход std::string::data используется вместо std::string объект.

Коррекция

Чтобы устранить эту проблему, избегайте неявной конструкции нового std::string объекты от выходных параметров std::string::c_str или std::string::data функции. Используйте существующий std::string объекты вместо этого.

#include <string>
#include <utility>
void CppLibFuncA(std::string const &);
void CppLibFuncB(std::string &&);
std::string make_string();
bool contains( std::string const& str1, std::string const& str2 )
{
	return str1.find( str2 ) == std::string::npos;
}
void foo(std::string const & s, std::string&& rs){
	CppLibFuncA( s ); 
	CppLibFuncB( std::move( rs ) ); 
	CppLibFuncA( make_string()); 
	if(contains(s,make_string())){
		//...
	}	
}

Зафиксируйте вызовы функций CppLibFunc, CppLibFuncB, и CppLibFuncC при помощи существующего std::string объекты, как введено.

#include <string>
#include <utility>
std::string make_string(void);
void bar(const std::string& s){
	std::string s1 = s.c_str(); // Inefficient
	std::string s2 = make_string();
	s2.append(s1.data());
}

В этом примере Polyspace отмечает явное использование струны до когда:

  • std::string объекты копируется в s1 путем вызова s.c_str().

  • std::string объект s1 добавлен, вызвав s1.data().

.

Коррекция

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

#include <string>
#include <string>
#include <utility>
std::string make_string(void);
void bar(const std::string& s){
	std::string s1 = s; // Efficient
	std::string s2 = make_string();
	s2.append(s1);
}
#include <string>
#include <utility>
std::string make_string(void);
void bar2( std::string& s1){
	std::string s2 = make_string();
	s1.replace(1, 1, &s2[0]);               
	s1.replace(s1.begin(), s1.end(), &s2.at(0));   
	s1.append(s2.c_str());                          
	s1.assign(s2.data());                         
	s1.compare(s2.data());
	const char* p = s2.c_str();
	s1.find(p);                            
}

В этом примере Polyspace отмечает явное использование струны до, чтобы вызвать функции членства std::string класс.

Коррекция

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

#include <string>
#include <string>
#include <utility>
std::string make_string(void);
void bar( std::string& s1){
	std::string s2 = make_string();
	s1.replace(1, 1, s2);               
	s1.replace(s1.begin(), s1.end(), s2);   
	s1.append(s2);                          
	s1.assign(s2);                         
	s1.compare(s2);                        
	s1.find(s2);                             
}
#include <string>
#include <utility>
void userDefined(const char* p){
	//...
}
void userDefined(const std::string& s){
	//...
	userDefined(s.c_str());//Compliant
	//userDefined(s);//Infinite recursion
}
void bar( const std::string& s){
	const char* p = s.data();    
	userDefined(p);
	userDefined(s.c_str());                         
}

В этом примере, пользовательском функциональном userDefined перегружается, чтобы принять любого const char* или const std::string параметр. Polyspace отмечает использование струны до вместо std::string объект вызвать функцию. Polyspace не отмечает вызовы std::string::c_str или std::string::data когда они используются для вызова const char* перегрузка userDefined от тела std::string перегрузка userDefined. В этом случае, использование std::string вместо струны до приводит к непреднамеренной бесконечной рекурсии.

Коррекция

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

#include <string>
#include <string>
#include <utility>
extern void userDefined(const char *);
extern void userDefined(const std::string &);
void bar( const std::string& s){                       
	userDefined(s);                     
}

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

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