如何有效地清除 std::queue ?

发布于 2024-07-16 09:56:39 字数 390 浏览 4 评论 0原文

我正在使用 std::queue 来实现 JobQueue 类。 (基本上这个类以先进先出的方式处理每个作业)。 在一种情况下,我想一次性清除队列(从队列中删除所有作业)。 我在 std::queue 类中没有看到任何明确的方法可用。

如何有效地实现 JobQueue 类的clear方法?

我有一个简单的循环弹出解决方案,但我正在寻找更好的方法。

//Clears the job queue
void JobQueue ::clearJobs()
 {
  // I want to avoid pop in a loop
    while (!m_Queue.empty())
    {
        m_Queue.pop();
    }
}

I am using std::queue for implementing JobQueue class. ( Basically this class process each job in FIFO manner).
In one scenario, I want to clear the queue in one shot( delete all jobs from the queue).
I don't see any clear method available in std::queue class.

How do I efficiently implement the clear method for JobQueue class ?

I have one simple solution of popping in a loop but I am looking for better ways.

//Clears the job queue
void JobQueue ::clearJobs()
 {
  // I want to avoid pop in a loop
    while (!m_Queue.empty())
    {
        m_Queue.pop();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

万水千山粽是情ミ 2024-07-23 09:56:39

清除标准容器的常见习惯用法是与容器的空版本进行交换:

void clear( std::queue<int> &q )
{
   std::queue<int> empty;
   std::swap( q, empty );
}

这也是实际清除某些容器(std::vector)内保存的内存的唯一方法

A common idiom for clearing standard containers is swapping with an empty version of the container:

void clear( std::queue<int> &q )
{
   std::queue<int> empty;
   std::swap( q, empty );
}

It is also the only way of actually clearing the memory held inside some containers (std::vector)

美男兮 2024-07-23 09:56:39

是的 - 队列类有点错误,恕我直言。 这就是我所做的:

#include <queue>
using namespace std;;

int main() {
    queue <int> q1;
    // stuff
    q1 = queue<int>();  
}

Yes - a bit of a misfeature of the queue class, IMHO. This is what I do:

#include <queue>
using namespace std;;

int main() {
    queue <int> q1;
    // stuff
    q1 = queue<int>();  
}
蓝眼泪 2024-07-23 09:56:39

在 C++11 中,您可以通过执行以下操作来清除队列:

std::queue<int> queue;
// ...
queue = {};

In C++11 you can clear the queue by doing this:

std::queue<int> queue;
// ...
queue = {};
红焚 2024-07-23 09:56:39

该主题的作者询问如何“有效”地清除队列,因此我假设他想要比线性O(队列大小)更好的复杂性。 由 David Rodriguez 提供的方法anon 具有相同的复杂性:
根据 STL 参考,operator = 的复杂度为 O(queue size)
恕我直言,这是因为队列的每个元素都是单独保留的,并且它没有像向量一样分配在一个大内存块中。 因此,要清除所有内存,我们必须分别删除每个元素。 因此,清除 std::queue 的最直接方法是一行:

while(!Q.empty()) Q.pop();

Author of the topic asked how to clear the queue "efficiently", so I assume he wants better complexity than linear O(queue size). Methods served by David Rodriguez, anon have the same complexity:
according to STL reference, operator = has complexity O(queue size).
IMHO it's because each element of queue is reserved separately and it isn't allocated in one big memory block, like in vector. So to clear all memory, we have to delete every element separately. So the straightest way to clear std::queue is one line:

while(!Q.empty()) Q.pop();
無處可尋 2024-07-23 09:56:39

显然,有两种最明显的方法可以清除 std::queue:与空对象交换和分配给空对象。

我建议使用赋值,因为它更快、更具可读性并且更明确。

我使用以下简单代码测量了性能,发现 C++03 版本中的交换比分配给空对象慢 70-80%。 然而,在 C++11 中,性能没有差异。 不管怎样,我会去完成任务。

#include <algorithm>
#include <ctime>
#include <iostream>
#include <queue>
#include <vector>

int main()
{
    std::cout << "Started" << std::endl;

    std::queue<int> q;

    for (int i = 0; i < 10000; ++i)
    {
        q.push(i);
    }

    std::vector<std::queue<int> > queues(10000, q);

    const std::clock_t begin = std::clock();

    for (std::vector<int>::size_type i = 0; i < queues.size(); ++i)
    {
        // OK in all versions
        queues[i] = std::queue<int>();

        // OK since C++11
        // std::queue<int>().swap(queues[i]);

        // OK before C++11 but slow
        // std::queue<int> empty;
        // std::swap(empty, queues[i]);
    }

    const double elapsed = double(clock() - begin) / CLOCKS_PER_SEC;

    std::cout << elapsed << std::endl;

    return 0;
}

Apparently, there are two most obvious ways to clear std::queue: swapping with empty object and assignment to empty object.

I would suggest using assignment because it simply faster, more readable, and unambiguous.

I measured performance using following simple code and I found that swapping in C++03 version works 70-80% slower than assignment to an empty object. In C++11 there is no difference in performance, however. Anyway, I would go with assignment.

#include <algorithm>
#include <ctime>
#include <iostream>
#include <queue>
#include <vector>

int main()
{
    std::cout << "Started" << std::endl;

    std::queue<int> q;

    for (int i = 0; i < 10000; ++i)
    {
        q.push(i);
    }

    std::vector<std::queue<int> > queues(10000, q);

    const std::clock_t begin = std::clock();

    for (std::vector<int>::size_type i = 0; i < queues.size(); ++i)
    {
        // OK in all versions
        queues[i] = std::queue<int>();

        // OK since C++11
        // std::queue<int>().swap(queues[i]);

        // OK before C++11 but slow
        // std::queue<int> empty;
        // std::swap(empty, queues[i]);
    }

    const double elapsed = double(clock() - begin) / CLOCKS_PER_SEC;

    std::cout << elapsed << std::endl;

    return 0;
}
暖伴 2024-07-23 09:56:39

您可以创建一个继承自队列的类并直接清除底层容器。 这是非常有效的。

template<class T>
class queue_clearable : public std::queue<T>
{
public:
    void clear()
    {
        c.clear();
    }
};

也许您的实现还允许您的 Queue 对象(此处为 JobQueue)继承 std::queue而不是将队列作为成员变量。 这样您就可以在成员函数中直接访问c.clear()

You could create a class that inherits from queue and clear the underlying container directly. This is very efficient.

template<class T>
class queue_clearable : public std::queue<T>
{
public:
    void clear()
    {
        c.clear();
    }
};

Maybe your a implementation also allows your Queue object (here JobQueue) to inherit std::queue<Job> instead of having the queue as a member variable. This way you would have direct access to c.clear() in your member functions.

悲欢浪云 2024-07-23 09:56:39

假设您的 m_Queue 包含整数:

std::queue<int>().swap(m_Queue)

否则,如果它包含指向 Job 对象的指针,则:

std::queue<Job*>().swap(m_Queue)

这样您就可以将空队列与您的 m_Queue 交换,因此 m_Queue 变空。

Assuming your m_Queue contains integers:

std::queue<int>().swap(m_Queue)

Otherwise, if it contains e.g. pointers to Job objects, then:

std::queue<Job*>().swap(m_Queue)

This way you swap an empty queue with your m_Queue, thus m_Queue becomes empty.

你げ笑在眉眼 2024-07-23 09:56:39

我这样做(使用 C++14):

std::queue<int> myqueue;
myqueue = decltype(myqueue){};

如果您有一个不平凡的队列类型,并且不想为其构建别名/typedef,则这种方法很有用。 不过,我总是确保围绕此用法留下评论,以向毫无戒心的/维护程序员解释这并不疯狂,并且是代替实际的 clear() 方法完成的。

I do this (Using C++14):

std::queue<int> myqueue;
myqueue = decltype(myqueue){};

This way is useful if you have a non-trivial queue type that you don't want to build an alias/typedef for. I always make sure to leave a comment around this usage, though, to explain to unsuspecting / maintenance programmers that this isn't crazy, and done in lieu of an actual clear() method.

累赘 2024-07-23 09:56:39

我不想依赖 swap() 或将队列设置为新创建的队列对象,因为队列元素没有正确销毁。 调用 pop() 会调用相应元素对象的析构函数。 这在 队列中可能不是问题,但很可能会对包含对象的队列产生副作用。

因此,如果您想防止可能的副作用,则使用 while(!queue.empty())queue.pop(); 的循环似乎是最有效的解决方案,至少对于包含对象的队列而言是如此。

I'd rather not rely on swap() or setting the queue to a newly created queue object, because the queue elements are not properly destroyed. Calling pop()invokes the destructor for the respective element object. This might not be an issue in <int> queues but might very well have side effects on queues containing objects.

Therefore a loop with while(!queue.empty()) queue.pop();seems unfortunately to be the most efficient solution at least for queues containing objects if you want to prevent possible side effects.

昔梦 2024-07-23 09:56:39

使用 unique_ptr 可能没问题。
然后重置它以获得一个空队列并释放第一个队列的内存。
至于复杂度? 我不确定 - 但猜想是 O(1)。

可能的代码:

typedef queue<int> quint;

unique_ptr<quint> p(new quint);

// ...

p.reset(new quint);  // the old queue has been destroyed and you start afresh with an empty queue

Using a unique_ptr might be OK.
You then reset it to obtain an empty queue and release the memory of the first queue.
As to the complexity? I'm not sure - but guess it's O(1).

Possible code:

typedef queue<int> quint;

unique_ptr<quint> p(new quint);

// ...

p.reset(new quint);  // the old queue has been destroyed and you start afresh with an empty queue
放手` 2024-07-23 09:56:39

另一种选择是使用简单的 hack 来获取底层容器 std::queue::c 并对其调用 clear 。 根据标准,该成员必须存在于 std::queue 中,但不幸的是 受保护。 这里的黑客取自这个答案

#include <queue>

template<class ADAPTER>
typename ADAPTER::container_type& get_container(ADAPTER& a)
{
    struct hack : ADAPTER
    {
        static typename ADAPTER::container_type& get(ADAPTER& a)
        {
            return a .* &hack::c;
        }
    };
    return hack::get(a);
}

template<typename T, typename C>
void clear(std::queue<T,C>& q)
{
    get_container(q).clear();
}

#include <iostream>
int main()
{
    std::queue<int> q;
    q.push(3);
    q.push(5);
    std::cout << q.size() << '\n';
    clear(q);
    std::cout << q.size() << '\n';
}

Another option is to use a simple hack to get the underlying container std::queue::c and call clear on it. This member must be present in std::queue as per the standard, but is unfortunately protected. The hack here was taken from this answer.

#include <queue>

template<class ADAPTER>
typename ADAPTER::container_type& get_container(ADAPTER& a)
{
    struct hack : ADAPTER
    {
        static typename ADAPTER::container_type& get(ADAPTER& a)
        {
            return a .* &hack::c;
        }
    };
    return hack::get(a);
}

template<typename T, typename C>
void clear(std::queue<T,C>& q)
{
    get_container(q).clear();
}

#include <iostream>
int main()
{
    std::queue<int> q;
    q.push(3);
    q.push(5);
    std::cout << q.size() << '\n';
    clear(q);
    std::cout << q.size() << '\n';
}
So尛奶瓶 2024-07-23 09:56:39

交换并不比“=”更有效。 。

template <class T> void swap (T& a, T& b)
{
  T c(std::move(a)); a=std::move(b); b=std::move(c);
}

交换只需使用 std::move 即可。 但对于空队列,std::move 是没有用的。

我的队列=空队列; 或 my_queue = std::move(empty_queue);

swap is not more efficient than "=". .

template <class T> void swap (T& a, T& b)
{
  T c(std::move(a)); a=std::move(b); b=std::move(c);
}

swap just use std::move. but for empty queue, std::move is useless.

my_queue = empty_queue; or my_queue = std::move(empty_queue);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文