Expensive return by value

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

Описание

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

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

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

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

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

    • Большой тривиально copyable объект. Возврат тривиально copyable объекта значением является более дорогим, когда объект является большим.

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

  • Недорогой, чтобы скопировать.

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

Риск

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

#include<string>
class Buffer{
public:
	//..
	const std::string getName() {
		return m_names;
	}
	//...
private:
	std::string m_names;
};
Класс Buffer содержит большой частный объект m_names. Распространено сделать, чтобы общедоступный метод get функционировал для такого частного объекта, такого как 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 получены доступ их функциями метода get.

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

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

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

Коррекция

Чтобы зафиксировать эти дефекты, возвратите большие объекты при помощи ссылок, как возвращают типы функций метода get. Например, установите тип возврата 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