cppcheck 警告:访问转发变量

cppcheck warning: access of forwarded variable

关于下面的代码

#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 运行 of cppcheck --enable=all 给出以下警告:

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)...);
                                                    ^

这个警告是什么意思,为什么会触发?

当你这样做时

f(std::forward<ArgsType>(args)...);

您正在使用完美转发将所有 args... 传递给 f。这意味着如果 args... 中的任何一个是右值,并且如果 f 从该右值移动到函数参数或函数内的变量,那么 args... 中的对象现在将是处于 moved from 状态,这意味着它的价值现在已经消失了。当你再使用 args...

g<1>(std::forward<F>(f), std::forward<ArgsType>(args)...);

您现在可以使用内容已被移动且不再可用于阅读的对象。这就是您收到警告的原因。如果要同时调用这两个函数,就不能使用完美转发了。

这是警告您,您的代码在潜在移动后使用了一个变量。

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

我们通过移动将 v 传递给函数(因此我们将右值引用传递给它)。当它将在调用 f(std::forward<ArgsType>(args)...) 中转发时,参数 v_ 将通过窃取 v 的内部来初始化。在此之后再次使用它(通过引用)是不明智的,因为它被定义为处于“有效但未指定的状态”。在这种状态下使用它可能会导致微妙且难以检测的问题。

除非类型记录在对象被移出后可以使用它,否则我们能做的唯一真正有效的操作就是为它分配一个新值。您的代码不会那样做。