Main Content

Variable read after move

A variable in a moved-from state is used in an operation that has preconditions

Since R2025a

Description

Polyspace® reports this defect when both of these conditions are true:

  • The content of an object is moved by using std::move(), leaving the object in a moved-from state.

  • The moved-from object is then used in an operation that has preconditions. Operations that have preconditions include reading the object, dereferencing the object, calling member functions of the object.

Some classes from the standard template library (STL) have a clear() method that resets the object to a specified state after a move. Calling the clear() method on moved-from objects of these classes and then reading them is not a defect.

Polyspace does not report this defect on objects of the following classes because their state after a move operation is specified in the C++ standard:

  • std::unique_ptr

  • std::shared_ptr

  • std::weak_ptr

  • std::unique_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

  • std::vector

Risk

If you use std::move() on an object, it can be in a valid but unspecified state. Using moved-from objects in operations that have preconditions can result in undefined behavior or logical errors.

Fix

To fix this defect, review your code and investigate why your code attempts to use moved-from objects. Reasons for this defect include:

  • Moving your local objects on their last use, but then later refactoring your code to add additional uses of the local objects. In such cases, either replace the move operation with a copy operation or refactor your code so that use of local object after the move is no longer necessary.

  • Attempting to use a moved-from container as an empty container. In such cases, clear the container by calling the clear() method before you use the container.

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

Examples

expand all

In this example, the parameters name and position in the function addEmployee() are moved to their destinations, which is efficient. The function log() is added in a later refactor for debugging purposes. Passing the moved-from objects to log() can result in undefined behavior. Polyspace reports this defect.

#include <string>
#include <set>
extern void log(const std::string &s1, const std::string &s2);
struct Employee
{
	std::string name;
	std::string position;
};

bool operator<(const Employee &e, const std::string &k) {
	return e.name < k;
}
bool operator<(const std::string &k, const Employee &e) {
	return k < e.name;
}
bool operator<(const Employee &e1, const Employee &e2) {
	return e1.name < e2.name;
}



static std::set<Employee> employees;

void addEmployee(std::string name, std::string position)
{
	Employee e;

	e.name = std::move(name);                              
	e.position = std::move(position);                      

	employees.insert(std::move(e));                        
	log("Added" + name, "in " + position);   /* Defect */
}


Correction — Place log() Function to Before Final Move Operation

Calling the function log() before the move operations fixes the defect.

#include <string>
#include <set>
extern void log(const std::string &s1, const std::string &s2);
struct Employee
{
	std::string name;
	std::string position;
};

bool operator<(const Employee &e, const std::string &k) {
	return e.name < k;
}
bool operator<(const std::string &k, const Employee &e) {
	return k < e.name;
}
bool operator<(const Employee &e1, const Employee &e2) {
	return e1.name < e2.name;
}



static std::set<Employee> employees;

void addEmployee(std::string name, std::string position)
{
	log("Added" + name, "in " + position);   /* No Defect */

	Employee e;
	e.name = std::move(name);                              
	e.position = std::move(position);                      

	employees.insert(std::move(e));                        

}


Result Information

Group: Programming
Language: C++
Default: Off
Command-Line Syntax: VAR_READ_AFTER_MOVE
Impact: Medium

Version History

Introduced in R2025a