首页 > 解决方案 > 为什么这个构造函数在传递给 std::thread 时被调用了 3 次?

问题描述

考虑这段代码:

class Widget {
public:
   Widget() { coutDefaultCtor();  }
   Widget(const Widget& w) { coutCopyCtor(); }
   Widget(Widget&& w) {  coutMoveCtor(); }

  ~Widget() = default; 

  void coutDefaultCtor() {
      std::cout << " called default Widget ctor " << std::endl;
  }

  void coutMoveCtor() {
      std::cout << " called move Widget ctor " << std::endl;
  }

  void coutCopyCtor() {
      std::cout << " called copy Widget ctor " << std::endl;
  }

  void doSomething() const { }
};

void takeWidget(const Widget& ref) {
  ref.doSomething();
}

int main() {
   Widget widget;

   std::thread t(takeWidget, widget);
   t.join();
   // expect 2 ctor calls
   // but calls 3
}   

据我所知,std::thread将始终按值复制参数。如果在某种情况下,入口点函数被定义为采用 r-value 或 const l-value 引用(此处相同),则在内部将创建一个临时类型并作为 r-value 传递。

上面代码的输出打印了" called Widget ctor "3 次。每个构造函数、默认值、复制和移动一个。

我只期待 2 次,一次用于widget调用默认构造函数main(),而创建的临时构造函数std::thread又被移动,为什么这里会发生另一个看似额外的构造?

标签: c++multithreading

解决方案


它是 C++ 标准库的一个实现细节,在不同的实现中可能会有所不同。std::thread t(takeWidget, widget)除了简单地调用之外,还有更多的事情发生takeWidget(widget)。例如,在 GCC 实现中,thread构造函数调用make_tuple()将根据参数类型移动或复制参数。


推荐阅读