循环

时间:2016-02-26 00:50:39

标签: c++ multithreading boost c++14 unique-ptr

。的变种 std::unique_ptr in a loop - memory leaks

在此修改后的问题中,RunSimulation()是一种成员方法。

我希望unique_ptr中的sim个对象(main())中的一个在main()内到期,而另一个对象(r)在main()内发送{ {1}} RunSimulation()释放class Result { public: int n; }; class Simulation { public: void RunSimulation(std::unique_ptr<Result> result) {result->n = 0;} }; void main() { boost::thread_group threads; std::unique_ptr<Result> r; std::unique_ptr<Simulation> sim = std::make_unique<Simulation>(); for (int i = 0; i < 10; i++) { r = std::unique_ptr<Result>(new Result); //Erroneous lines: //threads.create_thread(boost::bind(&Simulation::RunSimulation, boost::ref(sim), std::move(r))); //threads.create_thread([&] {sim->RunSimulation(std::move(r)); }); } threads.join_all(); } 。如果你能提供一个有效的代码,那就太好了。

// my-dialog.js
'use es6'
export default locals => ({
  locals, // will be bound to the controller instance!
  template:
`
<p>Something: <span>{{$ctrl.foo}}</span></p>
<md-button ng-click="$ctrl.onSave()">Save</md-button>
<md-button ng-click="$ctrl.cancel()">Cancel</md-button>
` ,
  bindToController: true,
  controllerAs: '$ctrl',
  controller: function($mdDialog, myService) {
    // this.foo = ..will be provided in locals as an input parameter..
    // this.onSave = () { ..will be provided as output parameter.. }
    this.cancel = () => {
      $mdDialog.cancel()
    }
  },
  clickOutsideToClose: true
})

1 个答案:

答案 0 :(得分:2)

您尝试将boost::bind创建的仿函数传递给create_thread的尝试失败,原因是我在answer中解释了您之前提问的原因。

使用lambda的尝试应该编译,但它有一个微妙的错误,将导致未定义的行为。我可能误解了你之前的回答,但这就是发布MCVE非常重要的原因。您在上一个问题中发布的小片段并未显示您打算如何使用该代码。

lambda的问题在于它只存储对unique_ptr的引用。在执行RunSimulation调用之前,您不会转让所有权,换句话说,只有在线程执行开始后才会进行所有权转移。但到那时for中的main循环可能已经转移到下一次迭代,导致上一次迭代中Result所持的unique_ptr被删除。取消引用unique_ptr中的RunSimulation会导致未定义的行为。

解决这个问题的方法是将unique_ptr的所有权立即转移到lambda,然后让lambda在调用RunSimulation时再次转让所有权。以下lambda表达式可以满足您的需求

[&sim, r=std::move(r)] () mutable {
    sim->RunSimulation(std::move(r));
}

为了解释发生了什么,lambda通过引用(sim)捕获&sim并且使用C ++ 14的lambda init捕获来将rmain的所有权转让给作为lambda成员的rr=std::move(r))(您可以将lambda&#39;成员r称为mutable如果你想要别的东西)。 lambda本身必须为const,因为您需要对r数据成员进行非move访问权限,以便在调用RunSimulationcreate_thread unique_ptr

不幸的是,这不是问题的结束。使用上面的lambda调用boost::thread仍然没有编译,因为根据documentation,它要求可调用对象是可复制的。你的lambda不可复制,因为它有一个thread_group数据成员。

解决方法是创建auto t = new boost::thread([&sim, r=std::move(r)] () mutable { sim->RunSimulation(std::move(r)); }); threads.add_thread(t); ,然后将add_thread创建为add_thread

add_thread

请注意,我无法找到thread_group所做的有关异常安全保障的任何文档。因此,如果在thread尝试将新线程添加到Result时发生异常,则您的RunSimulation对象可能会泄漏。

Live demo

最后,我认为您需要重新考虑您的设计。据推测,Result对象应该保存模拟结果。如果您在模拟结束后无法访问Result内的main,那么Resultmain存储在RunSimulation中的重点是什么?

正如我在上一个回答的评论中所建议的那样,您应该在Stuff中创建Object.constants.include? :Stuff #=> false 的容器,并将对这些容器的元素的引用传递给constant_missing。< / p>