Expensive std::string::c_str() use in a std::string operation

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

Описание

Этот дефект возникает, когда строковая операция выполняется с помощью указателя на C-строку, полученного из 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-string 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 объект, 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++
По умолчанию: Off
Синтаксис командной строки : EXPENSIVE_C_STR_STD_STRING_OPERATION
Влияние: Средний
Введенный в R2020b