exponenta event banner

Дороговизна по стоимости

Функции возвращают большие выходные данные по значению, а не по ссылке или указателю

Описание

Этот дефект возникает, когда функции возвращают большие выходные объекты по значению вместо объекта, возвращаемого по ссылке или указателю.

Эта проверка выполняется, если выполняются оба условия:

  • Адрес возвращенного объекта остается действительным после return заявление.

  • Возвращенный объект является одним из следующих:

    • Нетривиально копируемый объект. Возврат такого объекта по значению может потребовать вызова внешней функции, что дороже, чем возврат его по ссылке. Чтобы проверить, является ли объект нетривиально копируемым, используйте функцию std::is_trivially_copyable. Дополнительные сведения об этой функции см. в разделе std::is_trivially_copyable в ссылке C++.

    • Большой тривиально копируемый объект. Возврат тривиально копируемого объекта по стоимости дороже, когда объект большой.

Этот дефект не возникает, если возвращенный объект:

  • Недорого копировать.

  • Временный объект или нестатический локальный объект.

Риск

При возврате объекта по ссылке или указателю возвращать большой объект по значению неэффективно. Функции могут непреднамеренно возвращать большой объект по значению из-за отсутствия & или *. Такие неэффективные заявления о возврате могут быть не замечены. Рассмотрим этот код:

#include<string>
class Buffer{
public:
	//..
	const std::string getName() {
		return m_names;
	}
	//...
private:
	std::string m_names;
};
Класс Buffer содержит большой частный объект m_names. Для такого частного объекта обычно используется общедоступная функция получения, например, getName, который возвращает большой объект m_names. Потому что возвращаемый тип getNames устанавливается как const std::string вместо const std::string&функция возвращает большой объект по значению, а не по ссылке. Дорогой возврат копией может быть не замечен, поскольку этот код компилируется и функционирует правильно, несмотря на отсутствие &. Аналогичные источники неэффективности см. в разделе Expensive pass by value и Expensive copy in a range-based for loop iteration.

Зафиксировать

Чтобы устранить этот дефект, верните объекты с помощью ссылок. При использовании кода C используйте указатели, чтобы избежать возврата объектов по значению.

  • Чтобы вернуть объекты из функции C++ по ссылке, задайте возвращаемый тип функции в качестве ссылки. Например:

    #include<string>
    class Buffer{
    public:
    	//..
    	const std::string& getName() {
    		return m_name;
    	}
    	//...
    private:
    	std::string m_name;
    };
    Функция getName() возвращает большой объект m_names по ссылке, поскольку возвращаемый тип функции const std::string&, что является ссылкой.

  • Можно также использовать указатели, чтобы избежать возврата объектов по значению. Например, задайте возвращаемый тип getName() кому const std::string*, а затем вернуть адрес m_names как &m_names.

    #include<string>
    class Buffer{
    public:
    	//..
    	const std::string* getName() {
    		return &m_name;
    	}
    	//...
    private:
    	std::string m_name;
    };
    С помощью указателя функция getName() избегает возврата m_names по значению. Этот метод полезен в коде C, где ссылки недоступны.

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

Примеры

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

#include<string>
#include<memory>
#include<array>
#include<cstdint>
class Buffer{	
private:
	static const size_t SIZE = 10;
	std::string m_name; //Nontrivially copyable type
	std::array<uint8_t,SIZE> m_byteArray; // Large trivially copyable type 
	size_t m_currentSize; // Small trivially copyable
public:
	//...
	const std::string getName(){ 
		return m_name;
	}
	const std::array<uint8_t,SIZE> getByteArray(){ 
		return m_byteArray;
	}
	size_t getCurrentSize(){ 
		return m_currentSize;
	}
};

В этом примере различные частные объекты в классе Buffer доступны по их функциям-получателям.

  • Большой объект m_name возвращается функциями-получателями getName по значению. Возврат этого нетривиально копируемого объекта по значению неэффективен, когда его можно вернуть по ссылке. Polyspace ® помечает функцию.

  • Объект m_byteArray возвращается функцией-получателем getByteArray по значению. Возврат этого большого объекта по значению неэффективен, если его можно вернуть по ссылке. Polyspace помечает функцию.

  • Функция getCurrentSize возвращает целое число m_currentSize по значению. Копирование этого небольшого объекта не является неэффективным. Polyspace не помечает функцию.

Исправление

Чтобы исправить эти дефекты, верните большие объекты, используя ссылки в качестве типов возврата функций получения. Например, задайте возвращаемый тип getName кому const std::string& вместо const std::string.

#include<string>
#include<memory>
#include<array>
#include<cstdint>
class Buffer{	
private:
	static const size_t SIZE = 10;
	std::string m_name; //Nontrivially copyable type
	std::array<uint8_t,SIZE> m_byteArray; // Large trivially copyable type 
	size_t m_currentSize; // Small trivially copyable
public:
	//...
	const std::string& getName(){ 
		return m_name;	
	}
	const std::array<uint8_t,SIZE>& getByteArray(){ 
		return m_byteArray;
	}
	size_t getCurrentSize(){ 
		return m_currentSize;
	}
};
typedef struct _Circle{
	double Origin_abscissa;
	double Origin_ordinate;
	double Radius;
	char name[10];
}Circle;

const Circle getCircle(){
	static Circle SpecificCircle;
	//...
	return SpecificCircle;
}

В этом примере функция getCircle возвращает большое значение static объект SpecificCircle по значению. Polyspace помечает функцию.

Исправление

Чтобы устранить эту проблему, верните объект SpecificCircle с помощью указателя. Объявление возвращаемого типа функции getCircle как const Circle* вместо const Circle, а затем вернуть адрес объекта, то есть &SpecificCircle.

typedef struct _Circle{
	double O_abscissa;
	double O_ordinate;
	double Radius;
	char name[10];
}Circle;

const Circle* getCircle(){
	static Circle SpecificCircle;
	//...
	return &SpecificCircle;
}

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

Группа: Производительность
Язык: C | C++
По умолчанию: Откл.
Синтаксис командной строки: EXPENSIVE_RETURN_BY_VALUE
Воздействие: среднее
Представлен в R2020b