对于事件反应器和反应器中的超时,我使用优先级队列,该队列也允许O(log(n))随机访问事件的删除(当事件被发信号/完成而不是发生超时时)。我存储std::pair<std::chrono::steady_clock::time_point, Timed *>
其中Timed
是一个添加的类具有索引(指向队列),以便在调用TimedQ::Remove(Timed *p)
时有效删除。当我想要一个与超时相关联的事件类型时,我派生自Timed
。队列的Top()
和Pop()
会返回一对。
我以前使用队列有一堆代码,例如
std::tie(timePt0, eventPtr0) = timeoutQ.Pop();
std::tie(timePt1, eventPtr1) = std::move(hold);
在我开始在队列中使用基类Timed *
而不是特定事件类型之前工作正常(即Timed
最初是模板化类型),因为我最终需要支持多个不同的事件可以与超时关联的类型。但是,eventPtr*
是派生类型(我可以static_cast
来自队列返回的Timed *
),上面的代码不再有效。
我想知道最好的方法是什么。现在,它结果非常冗长,而且我也关注像临时创建这样的效率:
auto v(timeoutQ.Pop());
timePt0 = v.first;
eventPtr0 = static_cast<TimedEvent *>(v.second);
std::tie(timePt1, eventPtr1) = std::move(std::make_pair(hold.first, static_cast<TimedEvent *>(hold.second)); // I didn't literally do it like this, but I'm just trying to illustrate my struggle
我唯一的另一个想法是模拟派生事件类返回一对的函数,但从代码大小的角度看这似乎很差,因为即使机器代码应该是这样的,也会创建这些函数的多个实例相同,因为在所有情况下它都是一个存储的指针。
<小时/> 编辑: 我也试过使用它编译,但我不确定是正确还是有效:
template<class D>
std::pair<std::chrono::steady_clock::time_point, D *> &&Cnvrt(std::pair<std::chrono::steady_clock::time_point, Timed *> &&in)
{
return std::make_pair(in.first, static_cast<D *>(in.second));
}
然后最初的例子将成为
std::tie(timePt0, eventPtr0) = Cnvrt<std::remove_pointer<decltype(eventPtr0)>::type>(timeoutQ.Pop());
std::tie(timePt1, eventPtr1) = Cnvrt<std::remove_pointer<decltype(eventPtr1)>::type>(hold);
答案 0 :(得分:1)
您显示的Cnvrt
会返回悬空参考 - 经典UB。
这是一个更正的符合C ++ 11标准的版本,它在编译时也验证D
,并且无需在呼叫站点使用手册std::remove_pointer<...>::type
:
template<typename D>
constexpr
std::pair<std::chrono::steady_clock::time_point, D>
Cnvrt(std::pair<std::chrono::steady_clock::time_point, Timed*> const& in) noexcept
{
static_assert(std::is_pointer<D>{}, "D is not a pointer type");
using derived_type = typename std::remove_pointer<D>::type;
static_assert(std::is_base_of<Timed, derived_type>{}, "D does not derive from Timed");
using ptr_type = typename std::remove_cv<D>::type;
return {in.first, static_cast<ptr_type>(in.second)};
}
// ...
std::tie(timePt0, eventPtr0) = Cnvrt<decltype(eventPtr0)>(timeoutQ.Pop());
std::tie(timePt1, eventPtr1) = Cnvrt<decltype(eventPtr1)>(hold);
这是一个适用于VC ++ 2012的实现:
template<typename D>
std::pair<std::chrono::steady_clock::time_point, D>
Cnvrt(std::pair<std::chrono::steady_clock::time_point, Timed*> const& in) throw()
{
static_assert(std::is_pointer<D>::value, "D is not a pointer type");
typedef typename std::remove_pointer<D>::type derived_type;
static_assert(std::is_base_of<Timed, derived_type>::value, "D does not derive from Timed");
typedef typename std::remove_cv<D>::type ptr_type;
return std::make_pair(in.first, static_cast<ptr_type>(in.second));
}
这里没有任何效率问题 - 即使你的最坏情况场景,如果编译器根本没有优化,只是一个标量和一个指针的副本(VC ++ 2012可能会复制每个两次,但同样,只是没有启用优化)。