C++11 右值两次调用析构函数

标签 c++ multithreading c++11

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

所以我想利用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 , 看来我误解了 ground 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/

相关文章:

multithreading - 为什么 C++11acquire_release 栅栏不足以用于 Dekker 同步?

c++ - 添加 Sprite 时窗口关闭

c++ - 在相同状态类型的各种屏幕之间切换?

c# - 如果用不同数量的线程并行调用,为什么会得到不同的总和?

c++ - 计算独特项目的更好方法

c++ - 读取指向函数中的变量时出现段错误

C++ 静态变量初始化是原子的吗?

c++ - 排序几乎已排序的大文件

c# - WPF c# - 连续执行一个任务并允许执行另一个任务

C++ 应用程序不会终止