Main Content

AUTOSAR C++14 Rule A6-2-2

Expression statements shall not be explicit calls to constructors of temporary objects only

Description

Rule Definition

Expression statements shall not be explicit calls to constructors of temporary objects only.

Rationale

Objects that the compiler creates for a short duration, and then deletes, are temporary objects. The compiler might create temporary objects for specific purposes, such as:

  • Initializing references

  • Storing values returned by functions

  • Type casting

  • Exception handling

Temporary objects are destroyed once the expression that requires their construction is completely evaluated. For instance, in evaluating the expression sum = a*b+c, the compiler creates two temporary objects to store the results of the multiplication and addition operations. After the expression is evaluated, both temporary objects are destroyed. Their scope is limited to the expression statement.

If an expression is an explicit call to a constructor omitting the object name, the compiler creates a temporary object which is immediately destroyed. Such an explicit call to a constructor might indicate that:

  • You inadvertently omitted the object name.

  • You expected the unnamed variable to remain in scope up to the end of the declaration block.

Consider this code snippet where a lock_guard object is created.

void foo(){
std::mutex mymutex;
std::mutex mymutex2;
std::lock_guard<std::mutex> lock{mymutex};
std::lock_guard<std::mutex> {mymutex2};
//...
}
The first declaration creates a lock_guard object named lock. The object lock protects mymutex from concurrent access by multiple thread until the end of the current block. The second declaration attempts a similar protection for mymutex2. Because the lock_guard object in this case is not named, it is destroyed immediately after the declaration statement. Perhaps inadvertently, mymutex2 remains unprotected from concurrency issues.

Avoid expression statements that are only an explicit call to a constructor. To implement the Resource Acquisition Is Initialization (RAII) pattern, use named objects.

Polyspace Implementation

Polyspace® flags any expression statement that constructs an unnamed object and does not use it. You can construct unnamed temporary objects when you use the objects within the declaration expression statement. For example, a temporary object that is used as a function return or on the right-hand side of an assignment is compliant with this rule.

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

This code shows how Polyspace flags statements that are only explicit calls to a constructor.

#include <cstdint>
#include <fstream>
#include <string>
class MyException {
	MyException(const std::string &);
};
void with_exception() {
	MyException("Exception");              //Noncompliant
	throw MyException("Exception");        //Compliant 
	
};  

Polyspace flags an expression statement that constructs an unnamed temporary object and does not use it. If you use the temporary object in the statement, then the statement is compliant with the rule. For example, the statement MyException("Exception"); is flagged because the unnamed object created by the explicit call to the constructor MyException() is not used in the statement. The statement throw MyException("Exception"); is not flagged because the unnamed object is used as an argument to throw.

Compilers destroy an unnamed lock_guard object immediately after its declaration statement. Unnamed lock_guard objects cannot protect mutex objects from concurrency issues. Polyspace flags a statement when it declares an unnamed lock_guard object. Consider this code:

#include <cstdint>
#include <mutex>
class A {
public:
	void SetValue1(std::int32_t value) {
		std::lock_guard<std::mutex> {mutex1}; //Noncompliant
		private_value = value;
	}

	void SetValue2(std::int32_t value) {
		std::lock_guard<std::mutex> lock{mutex2}; //Compliant
		private_value = value;
	}
private:
	mutable std::mutex mutex1;
	mutable std::mutex mutex2;
	std::int32_t private_value;
};

  • The statement std::lock_guard<std::mutex> {mutex1}; declares an unnamed lock_guard object. Polyspace flags the statement.

  • The statement std::lock_guard<std::mutex> lock{mutex2}; is not flagged because the lock_guard object is named.

Check Information

Group: Statements
Category: Required, Automated