Search code examples
c++warningsperfect-forwardingcppcheck

cppcheck warning: access of forwarded variable


On the following code

#include <utility>

template <int i = 0, class F, typename... ArgsType>
void g(F&& f, ArgsType&&... args)
{
  if constexpr (i < 1) {
    f(std::forward<ArgsType>(args)...);
    g<1>(std::forward<F>(f), std::forward<ArgsType>(args)...);
  }
}

a run of cppcheck --enable=all gives the following warning:

Checking test.hpp ...
test.hpp:8:53: warning: Access of forwarded variable 'args'. [accessForwarded]
      g<1>(std::forward<F>(f), std::forward<ArgsType>(args)...);
                                                      ^
test.hpp:7:7: note: Calling std::forward(args)
      f(std::forward<ArgsType>(args)...);
        ^
test.hpp:8:53: note: Access of forwarded variable 'args'.
    g<1>(std::forward<F>(f), std::forward<ArgsType>(args)...);
                                                    ^

What does this warning mean and why is it triggered?


Solution

  • It's warning you that your code uses a variable after a potential move.

    std::vector<int> v{1, 2, 3};
    g([](auto v_) {  }, std::move(v));
    

    We pass v into the function by moving (so we pass an rvalue reference to it). When it will be forwarded in the invocation f(std::forward<ArgsType>(args)...), the argument v_ will be initialized by stealing the internal of v. Using it (via reference) again after that is ill-advised, since it's defined to be in a "valid, but unspecified state". Using it in such a state can potentially cause subtle and hard to detect problems.

    Unless a type documents its okay to use its objects after they have been moved from, the only truly valid operation we can do is assign it a new value. Your code doesn't do that.