动态分配的实现-Class std::async-ing 其成员
Dynamically-Allocated Implementation-Class std::async-ing its Member
考虑使用标准异步接口的操作:
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();
...
};
(除了对象使用指向自身的共享指针调用其方法的怪异之外,)问题在于标记为 [*]
的行。编译器(正确地)警告它是一个未使用的变量。
当然,有可能以某种方式欺骗它,但这是否表明存在根本问题?编译器是否有可能优化掉参数并将方法留在死对象中?整个方案有更好的替代方案吗?我发现生成的代码不是最直观的。
不,编译器不会优化参数。事实上,这是无关紧要的,因为生命周期延长来自 shared_from_this()
被衰减复制([thread.decaycopy])绑定到调用 [=13 的结果中=] ([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-captures 这会变得更简单:
std::async([self = shared_from_this()]{ self->do_op(); });
考虑使用标准异步接口的操作:
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();
...
};
(除了对象使用指向自身的共享指针调用其方法的怪异之外,)问题在于标记为 [*]
的行。编译器(正确地)警告它是一个未使用的变量。
当然,有可能以某种方式欺骗它,但这是否表明存在根本问题?编译器是否有可能优化掉参数并将方法留在死对象中?整个方案有更好的替代方案吗?我发现生成的代码不是最直观的。
不,编译器不会优化参数。事实上,这是无关紧要的,因为生命周期延长来自 shared_from_this()
被衰减复制([thread.decaycopy])绑定到调用 [=13 的结果中=] ([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-captures 这会变得更简单:
std::async([self = shared_from_this()]{ self->do_op(); });