考虑以下情况:
struct A {
// `unique_function` is like std::function but does not
// require its target to be Copyable, and is in turn
// itself not Copyable either.
unique_function<void()> callback = []{};
void set_callback(unique_function<void()> new_callback) {
callback = std::move(new_callback);
callback();
}
};
int main() {
A a;
a.set_callback([&, x = std::make_unique<int>(42)]{
std::cout << "Ok at this point, *x = " << *x << ".\n";
a.set_callback([]{}); // This destroys enclosing lambda
// while is is being executed, thus messing things up.
// Captures are not legal to access here.
});
}
在这种情况下,预期的语义是在设置它们时调用所有回调,并在最高callback
返回时将最后一个设置存储在set_callback
内。
我可以看到的解决方案:
将unique_function<void()>
替换为可复制的内容,例如std::shared_ptr<unique_function<void()>>
或专门的shared_function<void()>
,然后调用副本:
shared_function<void()> callback = []{};
void set_callback(shared_function<void()> new_callback) {
callback = std::move(new_callback);
auto callback_copy = callback;
callback_copy();
}
缺点:
有一个列表,并在执行之前附加回调。当返回页首set_callback
时,callbacks.back()
是最后一个回调集,其余的可以被删除。这需要额外的计数器跟踪当前set_callback
次呼叫的深度。
std::deque<unique_function<void()>> callbacks;
std::size_t depth = 0;
struct depth_controller {
std::size_t& depth;
depth_controller(std::size_t& d) : depth(d) { ++depth; }
~depth_controller() { --depth; }
};
void set_callback(shared_function<void()> new_callback) {
callbacks.emplace_back(std::move(new_callback));
{
depth_controller dctl{depth};
callbacks.back()();
}
if (depth > 0) { return; }
callbacks.erase(callbacks.begin(),
std::prev(callbacks.end()));
}
缺点:
我们可以做得更好吗?