如何有效清除std :: queue?

时间:2009-04-02 10:16:13

标签: c++ stl queue

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

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

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

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

11 个答案:

答案 0 :(得分:232)

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

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

它也是实际清除某些容器(std :: vector)

中保存的内存的唯一方法

答案 1 :(得分:41)

是的 - 有点像队列类的错误,恕我直言。这就是我的工作:

#include <queue>
using namespace std;;

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

答案 2 :(得分:21)

''David Rodriguez','anon' 该主题的作者询问如何“有效地”清除队列,因此我认为他希望复杂性高于线性O(队列大小)。您提供的方法具有相同的复杂性: 根据stl引用,operator =具有复杂度O(队列大小)。 恕我直言,因为队列的每个元素都是单独保留的,并且它不会分配在一个大的内存块中,就像在向量中一样。因此,为了清除所有内存,我们必须分别删除每个元素。因此,最简单的清除stl::queue的方法就是一行:

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

答案 3 :(得分:13)

显然,有两种最明显的方法可以清除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;
}

答案 4 :(得分:5)

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

$scope.totalPrice = 0;

        $scope.items = [{
            "item": "phone",
            "desc": "Iphone 4",
            "price": 100,
            "qty": 1
        }, {
            "item": "phone",
            "desc": "Iphone 5",
            "price": 200,
            "qty": 2
        }, {
            "item": "phone",
            "desc": "Iphone 6",
            "price": 300,
            "qty": 3
        }, {
            "item": "phone",
            "desc": "Iphone 7",
            "price": 400,
            "qty": 1
        }];
        $scope.updatePrice = function() {
            var total = 0;
            angular.forEach($scope.items, function(item) {
                total += item.qty * item.price;
            });
            $scope.totalPrice = total;
        };

        $scope.updatePrice();

答案 5 :(得分:4)

您可以创建一个从队列继承并直接清除基础容器的类。这非常有效。

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

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

答案 6 :(得分:1)

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

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

答案 7 :(得分:1)

假设您的m_Queue包含整数:

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

否则,如果包含例如指向Job对象的指针,然后:

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

通过这种方式,您与m_Queue交换了一个空队列,因此m_Queue变为空。

答案 8 :(得分:0)

使用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

答案 9 :(得分:0)

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

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

如果您不想为它构建别名/ typedef的非平凡队列类型,这种方法很有用。不过,我总是确保对这种用法发表评论,以向毫不怀疑/维护的程序员解释这并不疯狂,并且代替了实际的clear()方法。

答案 10 :(得分:0)

另一种选择是使用简单的技巧来获取基础容器std::queue::c并在其上调用clear。该成员必须按照标准出现在std::queue中,但不幸的是protected。此处的黑客来自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';
}