在 std::thread 中使用 std::move

using std::move in std::thread

我遇到了 std::thread 的另一个问题,这一次是在应用 std::move 交换 2 个值时。我的代码说:-

#include <iostream>
#include <thread>
using namespace std;
void swapno (int &&a, int &&b)
{
    int temp=move(a);
    a=move(b);
    b=move(temp);
}
int main()
{
    int x=5, y=7;
    cout << "x = " << x << "\ty = " << y << "\n";
//  swapno (move(x), move(y));  // this works fine
    thread t (swapno, move(x), move(y));
    t.join();
    cout << "x = " << x << "\ty = " << y << "\n";
    return 0;
}

输出:-

x = 5   y = 7
x = 5   y = 7

现在这个方法有什么问题?为什么这样的代码显示出这样的行为?我该如何更正它?

这是因为 thread constructor 你正在呼叫

copies/moves all arguments (both the function object f and all args...) to thread-accessible storage as if by the function:

template <class T>
typename decay<T>::type decay_copy(T&& v) {
    return std::forward<T>(v);
}

并且 std::decay 将删除 cv 限定符,其中包括 r 值引用。

因此,当 std::thread 是线程可访问存储的 copy/moving 个参数时,它本质上是从 它自己的 int您提供的那些,并且因为 int 上的 move 只是一个副本,所以当您对其值执行 swapno 时,您是在副本上执行此操作。

要更正它,请使用 std::ref 加上 swap:

std::thread t ([](int& a, int& b){std::swap(a, b);}, std::ref(x), std::ref(y));
t.join();

Live Demo

通俗地说,线程的构造函数接受 temporaries/rvalues 传递给函数的参数。因此,您必须用 reference_wrapper 包装它,这是一个值,但包装了底层引用(std::ref 所做的)。

下面的代码可以立即使用 std::swap。使用 std::swap 作为线程(或 std::function)的参数会导致模棱两可的过载(这也让我感到惊讶)。

int main(int argc, char* argv[])
{
  int x = 5, y = 7;
  std::cout << "x(" << x << ")" << " y(" << y <<")" << std::endl;
  void (*pf)(int& x, int& y) = std::swap<int>;
  std::thread t1(pf, std::ref<int>(x), std::ref<int>(y));
  t1.join();
  std::cout << "x(" << x << ")" << " y(" << y <<")" << std::endl;
  return 0;
}