std::queue 和 std::deque 清理

std::queue and std::deque cleanup

假设我们有一种情况需要 FIFO 数据结构。例如,按照事件进来的顺序消费一些事件。

此外,我们需要不时地清除整个队列。

std::queue 似乎非常适合这样做,但不幸的是它缺少清除容器的功能。

所以在这一点上,我们有两个选择:

std::queue

std::deque

总的来说,我们收到的要么太少要么太多,从来都不是我们真正想要的。

这是让我吃惊的事情,当我试图提供与 std::queue 一起使用的明确功能时,它是我的对象

的成员变量
struct message
{
};
struct consumer
{
    std::queue<message> _pending;

    void clear_ver_1()
    {
       auto will_be_deleted_when_out_of_scope = std::move(_pending);
    }

    void clear_ver_2()
    {
        std::queue<message> will_be_deleted_when_out_of_scope;
        _pending.swap(will_be_deleted_when_out_of_scope);
    }
};

我已经阅读了规格,但我不能确定 clear_ver_1 是否会使 _pending 处于 valid but unspecified 状态。请参阅那里的 string example

我很惊讶规范对这个主题如此含糊。我找错地方了吗?

谢谢大家!

更新

似乎分配和清除之间存在不可忽视的区别。在内部,queue 和 deque 几乎是一样的(一个正在使用另一个)

要清空队列,也可以简单写

_pending = {};

注意:第一种方法可能无效,不应依赖,因为 moved-form 对象处于有效但未指定的状态。

we got back what we asked for, but we've got too much: we also got push front and pop back

您得到了您想要的,dequeue 是一种允许在任一端点进行高效插入和删除的数据结构。它可能不是适合您的数据结构,但选择它是您的错。

we will have to "emulate" clear somehow, without the naive way of looping and popping

根据记录,弹出在性能方面非常便宜,它只是减少了一个数字。 while 循环中的弹出转换为将整数递减直到 0,除非您有 很多 个数字,否则速度非常快。事实上,它可能比分配内存快得多,这将我们带到:

清除这些集合的 STL 方法 类 是用一个空集合交换它们(这是您自己想出来的)或者直接 re-allocate 它们就位(苹果的回答)。这两者都将(可能,标准对这一点含糊不清)分配内存,这是一个非常昂贵的线性操作。

您已准备就绪,但我建议您进行概要分析,看看哪种方式对您来说真的很重要。就个人而言,我只是在一个循环中弹出队列,它会在下次我需要推送更多时将分配的内存留在原地,因此它可以节省潜在的多次分配和 re-allocations (与重置队列相比),具体取决于关于您拥有的数据量。

std::move

的用法

std::move 不应以这种方式使用。您应该只使用 std::move,好吧,当您不再使用对象时,将对象移动 到程序中的其他地方。正如您所说,它随后处于 有效但未指定的状态 :

  • 有效 因为它完全可以安全销毁;
  • 未指定 因为您不应再访问该对象。

std::queue 对比 std::deque

如果您只打算使用 FIFO 功能,我建议您使用 std::queue。它确实清楚地表明您将 std::deque 用作 FIFO 数据结构——清楚是 std::queue 存在的唯一原因.

清除 std::queue

您可以将它分配给一个空的 std::queue,或者像您所做的那样,将它换成一个空的。

// ...

struct consumer
{
    std::queue<message> _pending;

    void clearQueue()
    {
        _pending = {};
    }
};

根据DevSolar的评论编辑