Main Content

AUTOSAR C++14 Rule A12-8-3

Moved-from object shall not be read-accessed

Since R2021a

Description

Rule Definition

Moved-from object shall not be read-accessed.

Rationale

Because the content of a source object is generally unspecified after a move operation, it is unsafe to perform operations that access the contents of the source object after a move operation. Accessing the contents of the source object after a move operation might result in a data integrity violation, an unexpected value, or an illegal dereferencing of a pointer.

Operations that make no assumptions about the state of an object do not violate this rule.

The C++ standard specifies that these move operations leave the source object in a well-specified state after the move:

  • Move construction, move assignment, converting1 move construction, and converting move assignment of std::unique_ptr type

  • Move construction, move assignment, converting move construction, converting move assignment of std::shared_ptr type

  • Move construction and move assignment from a std::unique_ptr of std::shared_ptr type

  • Move construction, move assignment, converting move construction, and converting move assignment of std::weak_ptr type

  • std::move() of std::basic_ios type

  • Move constructor and move assignment of std::basic_filebuf type

  • Move constructor and move assignment of std::thread type

  • Move constructor and move assignment of std: unique_lock type

  • Move constructor and move assignment of std::shared_lock type

  • Move constructor and move assignment of std::promise type

  • Move constructor and move assignment of std::future type

  • Move construction, move assignment, converting move construction, and converting move assignment of std::shared_future type

  • Move constructor and move assignment of std::packaged_task type

Because these move operations leave the source object in a well-specified state, accessing the source object after calling these functions is compliant with this rule.

Polyspace Implementation

Polyspace® raises a flag if the source object is read after its contents are moved to a destination object by calling the std::move function explicitly. Polyspace does not flag accessing a source object if:

  • The source object of an explicit move operation is of these types:

    • std::unique_ptr

    • std::shared_ptr

    • std::weak_ptr

    • std::basic_ios

    • std::basic_filebuf

    • std::thread

    • std::unique_lock

    • std::shared_lock

    • std::promise

    • std::future

    • std::shared_future

    • std::packaged_task

  • The move operation is performed implicitly. For instance, the function std::remove moves objects implicitly. Polyspace does not flag accessing the object moved implicitly. To avoid accidentally accessing a moved object, erase the removed object using std::erase. For details about using std::remove, see Improper erase-remove idiom.

  • The source object is of a built-in base type, such as: int, enum, float, double, pointer, std::intptr_t, std::nullptr_t.

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 example shows how Polyspace flags reading the source object after an explicit move operation.

#include<string>
#include<iostream>
void F1()
{
	std::string s1{"string"};
	std::string s2{std::move(s1)}; 
	// ...
	std::cout
	<<  // Noncompliant
	s1
	<< "\n";
}

void F2()
{
	std::unique_ptr<std::int32_t> ptr1 = std::make_unique<std::int32_t>(0);
	std::unique_ptr<std::int32_t> ptr2{std::move(ptr1)};
	std::cout << ptr1.get() << std::endl; // Compliant by exception
}
void g(std::string v)
{
	std::cout << v << std::endl; 
}

void F3()
{
	std::string s;
	for (unsigned i = 0; i < 10; ++i) {
		s.append(1, static_cast<char>('0' + i));  //Noncompliant 
		g(std::move(s));
	}
}
void F4()
{
	for (unsigned i = 0; i < 10; ++i) {
		std::string s(1, static_cast<char>('0' + i)); // Compliant
		g(std::move(s));  
	}
}

  • In the function F1, string s1 is explicitly moved to s2 by calling std::move. After the move operation, the function attempts to read s1. Polyspace flags this attempt of reading a source object after an explicit move.

  • In the function F2, the unique pointer ptr1 is explicitly moved to ptr2. Because the std::unique_ptr remains in a specified state after the move, reading a source unique pointer after an explicit move is compliant with this rule.

  • In the function F3, the string s is explicitly moved, and then it is read by the std::string::append function. Polyspace flags this attempt of reading a source object after an explicit move.

  • In the function F4, the string s is explicitly moved. In each iteration of the loop, s is initiated to specific content before the move operation is triggered. As a result, the state of s is specified before the object is accessed. This method of accessing the source object after a move operation is compliant with this rule.

Check Information

Group: Special member functions
Category: Required, Partially automated

Version History

Introduced in R2021a


1 A converting constructor is a constructor that is not declared with the specifier explicit. See Converting constructor.