Main Content

AUTOSAR C++14 Rule A18-9-4

An argument to std::forward shall not be subsequently used

Since R2020b

Description

Rule Definition

An argument to std::forward shall not be subsequently used.

Rationale

You typically use std::forward in a function template to pass a forwarding reference parameter to another function. The resources of the parameter might be transferred to another object through a move operation, depending on the value category of the parameter.

For an rvalue parameter, the parameter is in an indeterminate state if it is moved from after the call to std::forward and it should not be reused.

For an lvalue parameter, If you reuse the parameter after the call to std::forward, modifications to the parameter might affect the argument of the caller function to which you pass the parameter.

Polyspace Implementation

Polyspace® flags the call to std::forward if the forwarded object is reused after the call. Polyspace also highlights the lines where the forwarded object is reused in your code.

Polyspace does not flag the call to std::forward if its argument is reused in a branch that cannot be reached after the call to std::forward. For instance, in this code snippet, the branch where the reuse of variable t occurs cannot be reached after the code enters the branch where std::forward is used.

template<typename T>
void func(T&& t)
{
  T&& p = t;

  switch(t) { 
    case 0:
      p = std::forward<T>(t); 
      break;
    case 1:
      t--; //t reused 
      break;
  }
}

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 <cstdint>
#include <iostream>
#include <utility>

namespace myTemplates
{

template <typename ...T>
void f1(T...t);

template<typename T>
void f2(T&& t2, bool b)
{
    if (b) {
        f1(std::forward<T>(t2)); // Compliant
    } else {
        t2++;  // else branch not entered
    }

}


template<typename T>
void f3(T&& t3)
{
    T&& p = std::forward<T>(t3); // Non-compliant

    switch (t3) {                // t3 reused
    case 0:
        t3++;                    // t3 reused
        break;
    case 1:
        t3--;                    // t3 reused
        break;
    default:
        break;
    }
}


template<typename T>
void f4(T&& t4)
{
    --t4;

    f1(std::forward<T>(t4)); // Non-compliant

    t4++;                    // t4 reused

    f1(std::forward<T>(t4)); // Non-compliant and t4 reused

    t4--;                    // t4 reused
}


template<typename T>
void f5(T&& t5)
{
    f1(t5,                   // t5 reused
       std::forward<T>(t5)); // Non-compliant
}

}

void main(void)
{
    int i;

    myTemplates::f2(i, true);
    myTemplates::f3(i);
    myTemplates::f4(i);
    myTemplates::f5(i);

}

In this example, Polyspace flags all the calls to std::forward where the forwarded parameter is reused after the call. In template function f4, the second call to std::forward counts as a reuse of the parameter t4. There are no violations of this rule in f2 because t2 is reused in the else branch which is never entered.

Check Information

Group: Language support library
Category: Required, Automated

Version History

Introduced in R2020b