我正在尝试制作一个类运行器(以固定的时间频率运行一个类),它在另一个线程中运行一个类,并且可以从主线程进行控制(如暂停、恢复、停止)。

所以我想利用 C++11 的 Functor 和其他特性。但是我有一个奇怪的问题,传递给 Runner 的 Functor 的析构函数被调用了两次。

#include <iostream>
#include <chrono>
#include <thread>

using namespace std;

class Runner {
 public:
  typedef function<bool()> fn_t;
  Runner(fn_t &&fn) : fn_(move(fn)), thread_(Thread, ref(*this)) {
    cout << "Runner" << endl;
  }
  ~Runner() {
    cout << "~Runner" << endl;
    thread_.join();
  }
 private:
  fn_t fn_;
  thread thread_;
  static void Thread(Runner &runner) {
    while (runner.fn_()) {
      cout << "Running" << endl;
      this_thread::sleep_for(chrono::milliumseconds(1));
    }
  }
};

class Fn {
 public:
  Fn() : count(0) {
    cout << "Fn" << endl;
  }
  ~Fn() {
    cout << "~Fn" << endl;
  }
  bool operator()() {
    return (++count < 5);
  }
 private:
  int count;
};

int main (int argc, char const* argv[])
{
  Fn fn;
  Runner runner(move(fn));
  return 0;
}

输出:
Fn
Runner
~Fn
~Runner
Running
Running
Running
Running
Running
~Fn
~Fn

如果我改变
Fn fn;
Runner runner(move(fn));


Runner runner(Fn());

该程序没有输出并停止。我试图禁用编译优化,没有任何变化。有什么解释吗?

我该如何解决这个问题或用其他方法做同样的事情?我应该像 std::async/std::thread 一样实现这个类吗?

更新到 Runner runner(Fn())
该语句作为函数声明被中断。
Runner runner((Fn())) 解决了问题。

感谢所有评论和答案。在查看 rvalue 之后,似乎我误解了来自地面 0 的右值引用的含义。我会尝试其他一些方法。

此问题的最终解决方案
#include <iostream>
#include <chrono>
#include <thread>
#include <vector>

using namespace std;

template<typename T, typename... Args>
class Runner {
 public:
  Runner(Args&&... args) :
      t(forward<Args>(args)...),
      thread_(Thread, ref(*this)) {
    cout << "Runner" << endl;
  }
  ~Runner() {
    cout << "~Runner" << endl;
    thread_.join();
  }
 private:
  T t;
  thread thread_;
  static void Thread(Runner &runner) {
    while (runner.t()) {
      cout << "Running" << endl;
      this_thread::sleep_for(chrono::milliseconds(100));
    }
  }
};

class Fn {
 public:
  Fn() : count(0) {
    cout << "Fn" << endl;
  }
  ~Fn() {
    cout << "~Fn" << endl;
  }
  bool operator()() {
    return (count++ < 5);
  }
 private:
  int count;
};

int main (int argc, char const* argv[])
{
  //vector<Fn> fns;
  //fns.emplace_back(Fn());
  Runner<Fn> runner;
  return 0;
}

输出:
Fn
Runner
~Runner
Running
Running
Running
Running
Running
~Fn

最佳答案

使用 std::move :

Runner(fn_t &&fn) : fn_(std::move(fn)), thread_(Thread, ref(*this)) {
    /*....*/
}

您需要明确使用 std::move ,否则它将被视为常量引用。您也可以使用 std::forward :
Runner(fn_t &&fn) : fn_(std::forward<fn_t>(fn)), thread_(Thread, ref(*this)) {
    /*....*/
}

关于C++11 右值调用析构函数两次,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10624764/

10-11 22:58
查看更多