Expensive return by value

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

Описание

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

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

  • Адрес возвращенного объекта остается действительным после 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. Общепринятая функция getter для такого частного объекта, как getName, который возвращает большой объект m_names. Потому что тип возврата getNames задается как const std::string вместо const std::string&функция возвращает большой объект по значению вместо по ссылке. Дорогой возврат по копии может быть не замечено, потому что этот код компилируется и функционирует правильно, несмотря на недостающие &. Для аналогичных источников неэффективности смотрите Expensive pass by value и Expensive copy in a range-based for loop iteration.

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

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

  • Чтобы вернуть объекты из функции 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 по значению. Этот метод полезен в коде С, где ссылки недоступны.

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

Примеры

расширить все

#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 доступ к ним осуществляется с помощью функций getter.

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

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

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

Коррекция

Чтобы исправить эти дефекты, верните большие объекты с помощью ссылок возврата качестве типов функций getter. Для образца установите тип возврата 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++
По умолчанию: Off
Синтаксис командной строки : EXPENSIVE_RETURN_BY_VALUE
Влияние: Средний
Введенный в R2020b