This is a draft version of a MISRA C++ 202x rule proposed for public review.
MISRA Rule 28.6.3
Category: Required
Analysis Type: Decidable, Single Translation Unit
Amplification
Calling std::move
, std::forward
or an equivalent static_cast
puts its argument into a potentially
moved-from state.
An object in a potentially moved-from state shall not be used on any path, regardless of the path’s feasibility.
An object passed as an lvalue reference function parameter shall not be in a potentially moved-from state when the function
returns. This additional restriction is included as it allows compliance to be determined within a translation unit.
This rule does not apply to the following:
- Assigning to an object; or
- Destroying an object; or
- Using an object having type
std::unique_ptr
.
For the purposes of this rule, aliases of an object are considered to refer to different objects. This allows compliance checks to be
decidable.
Rationale
Using std::forward
or std::move
on an lvalue to pass it as an rvalue reference argument in a function
call can result in the lvalue object being in an indeterminate state after the call. However, a std::unique_ptr
that has been
moved-from is in a well-defined state, equal to nullptr
.
Example
size_t a( std::string s1 )
{
std::string s2 = std::move( s1 );
return s1.size(); // Non-compliant - s1 has potentially
} // moved-from state
size_t b( std::string s1 )
{
std::string s2 =
static_cast< std::string && >( s1 ); // Equivalent to std::move
return s1.size(); // Non-compliant - s1 has potentially
} // moved-from state
void c( std::string s1 )
{
std::string s2 = std::move( s1 );
std::string s3 = s1; // Non-compliant - s1 has potentially
} // moved-from state
template< typename T >
void bar( T & t );
template< typename T >
void foo( T && t )
{
bar( std::forward< T >( t ) );
++t; // Non-compliant - std::forward leaves t
} // in a potentially moved-from state
struct X { std::string s; };
void f( X & x )
{
X y ( std::move( x ) ); // Non-compliant - lvalue reference
// parameter left in potentially moved-
} // from state when function returns
void g( X x )
{
X y;
y = std::move( x ); // Compliant - no more uses of x
}
void h( X x )
{
X y;
y = std::move( x );
x = X{}; // Compliant - assigns to potentially
} // moved-from object
The following example is non-compliant as the evaluation order of the arguments to d1
is implementation-defined and there is
a permitted order in which the first argument s
has potentially moved-from state.
void d1 ( std::string const &, int32_t );
int32_t d2 ( std::string && );
void d3( std::string s )
{
d1( s, d2( std::move( s ) ) ); // Non-compliant
}
Copyright The MISRA Consortium Limited © 2023