对于事件反应器和proactor中的超时,我使用一个优先级队列,该队列还允许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 *转换为ojit_code),因此上述代码不再起作用。

我想知道什么是最好的方法。现在,它最终变得非常冗长,而且我也担心会产生临时性这样的效率:
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);

最佳答案

您显示的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);

Online Demo

这是一个可以在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));
}

Online Demo

无论如何,这里都没有效率问题–即使在最坏的情况下,如果编译器根本不进行优化,也只是一个标量和一个指针的副本(VC++ 2012可能会复制两次,但是同样,只有在未启用优化的情况下) 。

关于c++ - std::pair分配向下,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35054983/

10-12 16:48