考虑使用标准异步接口的操作:
std::future<void> op();
在内部,op
需要执行(可变)数量的异步操作才能完成;这些操作的数量是有限的但无限制的,并且取决于先前异步操作的结果。
这是一次(糟糕的)尝试:
/* An object of this class will store the shared execution state in the members;
* the asynchronous op is its member. */
class shared
{
private:
// shared state
private:
// Actually does some operation (asynchronously).
void do_op()
{
...
// Might need to launch more ops.
if(...)
launch_next_ops();
}
public:
// Launches next ops
void launch_next_ops()
{
...
std::async(&shared::do_op, this);
}
}
std::future<void> op()
{
shared s;
s.launch_next_ops();
// Return some future of s used for the entire operation.
...
// s destructed - delayed BOOM!
};
问题当然是s
超出了范围,因此以后的方法不起作用。
要修改此内容,以下是更改:
class shared : public std::enable_shared_from_this<shared>
{
private:
/* The member now takes a shared pointer to itself; hopefully
* this will keep it alive. */
void do_op(std::shared_ptr<shared> p); // [*]
void launch_next_ops()
{
...
std::async(&shared::do_op, this, shared_from_this());
}
}
std::future<void> op()
{
std::shared_ptr<shared> s{new shared{}};
s->launch_next_ops();
...
};
(除了使用共享指针调用其方法的对象的古怪之外),问题在于标记为[*]
的行。编译器(正确)警告它是一个未使用的变量。
当然,有可能以某种方式欺骗它,但这是否是一个基本问题的迹象?编译器是否有可能优化掉参数并使方法留下死对象?这整个计划有更好的替代方案吗?我发现最终的代码不是最直观的。
答案 0 :(得分:1)
不,编译器不会优化掉参数。实际上,这是无关紧要的,因为终身扩展来自shared_from_this()
被衰变复制( [thread.decaycopy] )绑定到调用std::async
的结果中( [futures.async] 强> / 3)。
如果您想避免使用未使用的参数的警告,请将其保留为未命名;警告未使用的参数的编译器不会对未使用的未命名参数发出警告。
另一种方法是制作do_op
static
,这意味着您必须使用其shared_ptr
参数;这也解决了this
和shared_from_this
之间的重复问题。由于这非常麻烦,您可能希望使用lambda将shared_from_this
转换为this
指针:
std::async([](std::shared_ptr<shared> const& self){ self->do_op(); }, shared_from_this());
如果你可以使用C ++ 14 init-capture,那就更简单了:
std::async([self = shared_from_this()]{ self->do_op(); });