exponenta event banner

Дорого std::string::c_str() использование в std::string операция

Строковая операция использует выходные данные std::string::c_str способ, приводящий к неэффективному коду

Описание

Этот дефект возникает, когда строковая операция выполняется с помощью указателя C-string, полученного из std::string::c_str. Например, эта проверка поднимается, когда:

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

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

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

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

Риск

Использование C-строкового выхода std::string::c_ctr метод, когда можно использовать std::string вместо этого объект. Один std::string содержит длину строки. При использовании вывода C-строки std::string::c_str вместо метода std::string объект, конструктор определяет длину C-строки линейным поиском, что приводит к неэффективному коду. Используя std::string::c_str также часто является ненужным. Рассмотрим этот код:

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 требует C-строку в качестве входных данных, используя 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_str около 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.c_str() ) == std::string::npos;
}

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

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

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

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

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

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

Исправление

Чтобы устранить эту проблему, избегайте неявного построения новых std::string объекты из выходных данных std::string::c_str функция. Вы можете пропустить вызов для std::string::c_str в вызовах функций и использовать существующие 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::c_str и вместо этого с использованием существующего 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.c_str());
}

В этом примере Polyspace помечает явное использование std::string::c_str для копирования std::string объект s кому s1. Содержание s1 также прилагается к s2 с помощью s1.c_str(). Polyspace помечает использование C-строки в std::string::append() функция.

Исправление

Чтобы устранить эту проблему, избегайте использования std::string::c_str когда вы можете использовать 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 bar( std::string& s1){
	std::string s2 = make_string();
	s1.replace(1, 1, s2.c_str());               
	s1.replace(s1.begin(), s1.end(), s2.c_str());   
	s1.append(s2.c_str());                          
	s1.assign(s2.c_str());                         
	s1.compare(s2.c_str());                        
	s1.find(s2.c_str());                            
}

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

Исправление

Чтобы устранить эту проблему, избегайте использования std::string::c_str когда вы можете использовать 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);                            
	s1.find(s2); 
}
#include <string>
#include <utility>
extern void userDefined(const char *);
extern void userDefined(const std::string &);
void bar( const std::string& s){
	const char* p = s.c_str();    
	userDefined(p);
	userDefined(s.c_str());                         
}

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

Исправление

Чтобы устранить эту проблему, избегайте использования строк C при использовании 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++
По умолчанию: Откл.
Синтаксис командной строки: EXPENSIVE_C_STR_STD_STRING_OPERATION
Воздействие: среднее
Представлен в R2020b