Main Content

Expensive return by value

Functions return large output by value instead of by reference or pointer

Since R2020b

Description

This defect occurs when functions return large output objects by value instead of the object being returned by reference or pointer.

This checker is raised if both of these conditions are true:

  • The address of the returned object remains valid after the return statement.

  • The returned object is any of these:

    • A nontrivially copyable object. Returning such an object by value might require an external function call, which is more expensive than returning it by reference. To check whether an object is nontrivially copyable, use the function std::is_trivially_copyable. For more details about this function, see std::is_trivially_copyable in the C++ reference.

    • A large trivially copyable object. Returning a trivially copyable object by value is more expensive when the object is large.

This defect is not raised if the returned object is:

  • Inexpensive to copy.

  • A temporary object or a nonstatic local object.

Risk

It is inefficient to return a large object by value when you can return the object by reference or pointer. Functions might inadvertently return a large object by value because of a missing & or *. Such inefficient return statements might not be noticed. Consider this code:

#include<string>
class Buffer{
public:
	//..
	const std::string getName() {
		return m_names;
	}
	//...
private:
	std::string m_names;
};
The class Buffer contains a large private object m_names. It is common to have a public getter function for such a private object, such as getName, which returns the large object m_names. Because the return type of getNames is set as const std::string instead of const std::string&, the function returns the large object by value instead of by reference. The expensive return by copy might not be noticed because this code compiles and functions correctly despite the missing &. For similar sources of inefficiency, see Expensive pass by value and Expensive copy in a range-based for loop iteration.

Fix

To fix this defect, return objects by using references. When using C code, use pointers to avoid returning objects by value.

  • To return objects from a C++ function by reference, set the return type of the function as a reference. For instance:

    #include<string>
    class Buffer{
    public:
    	//..
    	const std::string& getName() {
    		return m_name;
    	}
    	//...
    private:
    	std::string m_name;
    };
    The function getName() returns the large object m_names by reference because the return type of the function is const std::string&, which is a reference.

  • Alternatively, use pointers to avoid returning objects by value. For instance, set the return type of getName() to const std::string*, and then return the address of m_names as &m_names.

    #include<string>
    class Buffer{
    public:
    	//..
    	const std::string* getName() {
    		return &m_name;
    	}
    	//...
    private:
    	std::string m_name;
    };
    By using a pointer, the function getName() avoids returning m_names by value. This method is useful in C code where references are not available.

    Performance improvements might vary based on the compiler, library implementation, and environment that you are using.

Examples

expand all

#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;
	}
};

In this example, various private objects in the class Buffer are accessed by their getter functions.

  • The large object m_name is returned by the getter functions getName by value. Returning this nontrivially copyable object by value is inefficient when it can be returned by reference instead. Polyspace® flags the unction.

  • The object m_byteArray is returned by the getter function getByteArray by value. Returning this large object by value is inefficient when it can be returned by reference instead. Polyspace flags the function.

  • The function getCurrentSize returns the integer m_currentSize by value. Copying this small object is not inefficient. Polyspace does not flag the function.

Correction

To fix these defects, return large objects by using references as return types of the getter functions. For instance, set the return type of getName to const std::string& instead of 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;
}

In this example, the function getCircle returns the large static object SpecificCircle by value. Polyspace flags the function.

Correction

To fix this issue, return the object SpecificCircle by using a pointer. Declare the return type of the function getCircle as const Circle* instead of const Circle, and then return the address of the object, that is, &SpecificCircle.

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

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

Result Information

Group: Performance
Language: C | C++
Default: Off
Command-Line Syntax: EXPENSIVE_RETURN_BY_VALUE
Impact: Medium

Version History

Introduced in R2020b