Main Content

AUTOSAR C++14 Rule A8-4-5

"consume" parameters declared as X && shall always be moved from

Since R2021a

Description

Rule Definition

"consume" parameters declared as X && shall always be moved from.

Rationale

When declaring a function, you might indicate your intention of moving the content of a function parameter by declaring it as a nonconst and nontemplate rvalue reference or a "consume" (X&&) parameter. For instance, the parameter of this function is declared as a "consume" parameter: void foo(std::vector<std::string>&& V). This declaration implies that the content of the vector V is intended to be moved instead of copied within the body of the function.

When you declare a function parameter as a "consume" parameter, use move semantics when using the parameter. Within the body of the function, use the std::move function explicitly if you use an lvalue reference to invoke the function.

Polyspace Implementation

Polyspace® flags the definition of a function if both of these conditions are true:

  • At least one function parameter is declared as a nonconst and nontemplate rvalue reference, that is, a "consume" or X&& parameter.

  • The content of the X&& parameter is not completely moved to another object by using the std::move function within the body of the function.

Polyspace does not report violation of this rule on move constructors and move assignment operators.

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

#include <utility>
class C
{
	C(C&& c): a{std::move(c.a)}     // Compliant by exception.
	{
	}

	C& operator=(C&& c)             // Compliant by exception.
	{
		a = std::move(c.a);

		return *this;
	}

	void move(C&& c)                // Noncompliant
	{
		a = std::move(c.a);//Partial move
	}

	void cond(C&& c, bool b)        // Compliant
	{
		if (b) {
			move(std::move(c));
		} else {
			a++;
		}
	}
public:
	int a;
	void set(int&& num)     // Compliant
	{
		a = std::move(num);
	}
	void set1(int&&)     // Noncompliant
	{
		//Unnamed temporary variable cannot be moved from.
	}
	void set2(int&& i12);  // Violation raised on definition.
	void set3(int&& i11a,  // Noncompliant
	int&& i11b)  // Noncompliant
	{
		if(i11a != i11b)
		{
		}
	}
	
};
void C::set2(int&& i12)   // Noncompliant
{
	a = i12;
}

template<typename T>
void tf1(T&& t1)      // Compliant - not a "consume" parameter
{
}

In this example, the data member a of the class C is set to an integer by using move semantics.

  • Polyspace does not flag the move constructor and the move assignment operator even though these functions do not completely move the "consume" or X&& parameter. These functions are compliant by exception.

  • Polyspace flags the function C::move because the body of the function partially moves the "consume" or X&& parameter.

  • Polyspace flags the function C::set1 because this function uses an unnamed "consume" parameter. Because the parameter is unnamed, you cannot use the function std::move on this X&& parameter.

  • Polyspace flags the function C:: set2 because the body of the function copies the "consume" parameter instead of using the function std::move. Polyspace raises the violation on the definition of the variable. Similarly, the function C::set2 is also noncompliant with this rule because its body does not use std::move on X&& variables.

  • The function C::cond and C::set are compliant with this rule because the bodies of these functions use std::move on the "consume" parameters.

  • Polyspace does not flag the function template because this rule does not apply to templates.

Check Information

Group: Declarators
Category: Required, Automated

Version History

Introduced in R2021a