189

JobQueue クラスの実装に std::queue を使用しています。(基本的に、このクラスは各ジョブをFIFO方式で処理します)。あるシナリオでは、一発でキューをクリアしたい (キューからすべてのジョブを削除する)。std::queue クラスで使用できる明確なメソッドがありません。

JobQueue クラスの clear メソッドを効率的に実装するにはどうすればよいですか?

ループをポップする簡単な解決策が1つありますが、より良い方法を探しています。

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

11 に答える 11

290

標準コンテナをクリアするための一般的なイディオムは、空のバージョンのコンテナと交換することです:

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

また、一部のコンテナ (std::vector) 内に保持されているメモリを実際にクリアする唯一の方法でもあります。

于 2009-04-02T10:23:56.143 に答える
53

はい - キュー クラス、IMHO のちょっとした不具合です。これが私がすることです:

#include <queue>
using namespace std;;

int main() {
    queue <int> q1;
    // stuff
    q1 = queue<int>();  
}
于 2009-04-02T10:19:44.267 に答える
33

トピックの作成者は、キューを「効率的に」クリアする方法を尋ねたので、線形O(queue size)よりも複雑さを求めていると思います。David Rodriguezが提供するメソッドの複雑さは同じです。STLリファレンスによると、operator =複雑さはO(queue size)です。IMHOは、キューの各要素が個別に予約されており、ベクターのように1つの大きなメモリブロックに割り当てられていないためです。したがって、すべてのメモリをクリアするには、すべての要素を個別に削除する必要があります。したがって、クリアする最も簡単な方法std::queueは 1 行です。

while(!Q.empty()) Q.pop();
于 2010-08-30T11:12:42.053 に答える
19

どうやら、クリアするには2つの最も明白な方法があり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;
}
于 2015-02-25T16:54:05.563 に答える
18

C++11 では、次のようにしてキューをクリアできます。

std::queue<int> queue;
// ...
queue = {};
于 2016-09-23T08:19:52.340 に答える
1

別のオプションは、単純なハックを使用して、基になるコンテナーを取得し、それstd::queue::cを呼び出すclearことです。std::queueこのメンバーは、標準に従ってに存在する必要がありますが、残念ながらprotected. ここでのハックは、この回答から取られました。

#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';
}
于 2018-12-14T14:39:26.760 に答える
1

を使用して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
于 2015-01-10T17:38:07.543 に答える