涼の成長記録

自らの人生に主導権を持つべく、独立を目指して2014年3月31日を持ってITエンジニアを退職。そんな23歳♂の成長記録。

コンテナがクラスのpriority_queue

優先度キューに抱いていた勝手な幻想

STLのpriority_queue、つまり優先度キューのお話です。
priority_queue - C++ Reference


今作っているアプリケーションで、priority_queueのコンテナをクラスにして、それらを優先度順にプッシュできれば、いい感じに作れそうなモジュールがあります。priority_queueは使ったことがないのですが、何となく以下のような感じでいけると思っていました。勝手な幻想を抱いていたものです。

// 優先度キューで管理するコンテナ
class TContainer {
    public:
        // コンストラクター
        TContainer(string message) : m_Message(message) {}

        // メッセージを返すアクセサメソッド
        string getMessage() {
            return m_Message;
        }

    private:
        const string m_Message;
}

// メイン
void main() {
    priority_queue<TContainer> priorityQueue;
    
    // 中・低・高の順でプッシュするけど第二引数で優先度を指定する。
    priorityQueue.push(TContainer("優先度:中"), 2);
    priorityQueue.push(TContainer("優先度:低"), 1);
    priorityQueue.push(TContainer("優先度:高"), 3);
    
    // すると、高・中・低の順に並び変わっている、という勝手な幻想。
    while (!priorityQueue.empty()) {
        cout << priorityQueue.top().getMessage() << endl;
        priorityQueue.pop();
    }
}

現実

まあ、結論から言うと、こんなことはできないのです。私の手元の入門書籍や、WEBサイトを見て回ったところ、int型のコンテナを管理するqueueがに、そのint型の値順にソートするサンプルしか見つからないのです。こんな感じです。

void main() {
    priority_queue<int> priorityQueue;
    
    priorityQueue.push(2);
    priorityQueue.push(1);
    priorityQueue.push(3);
    
    while (!priorityQueue.empty()) {
        cout << priorityQueue.top() << endl;
        priorityQueue.pop();
    }
}

対策コード

こんなの俺が思っている優先度キューじゃない!ということで、自分で無理矢理やることにしました。とりあえず完成したコードを見てください。

#include <iostream>
#include <queue>
#include <string>

using namespace std;

// 優先度キューで管理するコンテナ
class TContainer {
    public:
        // コンストラクター
        TContainer(string message, unsigned int priority) :
            m_Message(message), m_Priority(priority) {}
        
        // 比較演算子のオーバーロード
        bool operator < (const TContainer &container) const {
            return (m_Priority <  container.m_Priority);
        }
        
        // メッセージを返すアクセサメソッド
        string getMessage() {
            return m_Message;
        }

    private:
        // メッセージ
        const string m_Message;

        // 優先度(数値が大きいほど高い)
        const unsigned int m_Priority;
};

// メイン
void main() {
    priority_queue<TContainer, vector<TContainer>, less<TContainer> > priorityQueue;
    
    // 中・低・高の順でプッシュするけど
    priorityQueue.push(TContainer("優先度:中", 2));
    priorityQueue.push(TContainer("優先度:低", 1));
    priorityQueue.push(TContainer("優先度:高", 3));
    
    // 高・中・低の順に並び変わっているのだ。
    while (!priorityQueue.empty()) {
        cout << priorityQueue.top().getMessage() << endl;
        priorityQueue.pop();
    }
}

説明

要はソートの条件があれば良いわけです。まず、コンテナのクラスに優先度のメンバーを作ります。メンバーはコンストラクターで与えられます。

private:
    // 優先度(数値が大きいほど高い)
    unsigned int m_Priority;


そして、ソートするために比較演算子をオーバーロードします。

// 比較演算子のオーバーロード
bool operator < (const TContainer &container) const {
    return (m_Priority <  container.m_Priority);
}


これだけです。簡単ですね。あとは、プッシュする時はこんな感じです。

priorityQueue.push(TContainer("優先度:中", 2));


という感じで、めでたく幻想を現実にすることができました。少しC++らしいことが自力でできて嬉しいです。
ではでは。