キュー改良

Exceptionの練習としてデータ範囲のチェックと,空のキューも使えるようにした.前回のキューだと1個以上データがないと使えないとかあった.

一応,メモリリークしないことも確認した.valgrind使ってみた.

// queue.cpp
#include <iostream>
#include <string>

class queue_exception
{
    public:
        const std::string message;
        queue_exception(const std::string &m) : message(m) {};
};

class queue_items
{
    public:
        const int data;
        queue_items *next_ptr;

        queue_items(const int &);
};

queue_items::queue_items(const int &i = 0) : data(i)
{
    next_ptr = NULL;
}

class queue
{
    public:
        queue_items *last_ptr;
        queue_items *first_ptr;

        queue();
        queue(queue_items *);
        static queue* initialize();
        static queue* initialize(int);
        ~queue();
        void enq(const int i);
        int deq();
        void print_all();
        bool is_empty();

    private:
};

queue::queue()
{
    first_ptr = NULL;
    last_ptr = NULL;
}

queue::queue(queue_items *i)
{
    first_ptr = i;
    last_ptr = first_ptr;
}

queue::~queue()
{
    // ちゃんと queue_items を全部 delete する
    queue_items *tmp;
    while(first_ptr != NULL) {
        tmp = first_ptr;
        first_ptr = first_ptr->next_ptr;
        delete tmp;
    }
}

queue* queue::initialize()
{
    return new queue();
}

queue* queue::initialize(const int i)
{
    return new queue(new queue_items(i));
}

void queue::enq(const int i)
{
    queue_items *new_ptr;

    new_ptr = new queue_items(i);

    if (last_ptr == NULL) {
        last_ptr = new_ptr;
        first_ptr = last_ptr;
    }
    else {
        last_ptr->next_ptr = new_ptr;
        last_ptr = last_ptr->next_ptr;
    }
}

bool queue::is_empty()
{
    if (first_ptr == NULL) {
        return true;
    }
    return false;
}

int queue::deq()
{
    // 範囲内チェック
    if (first_ptr == NULL) {
        throw queue_exception("queue is out of data.");
    }

    int tmp = first_ptr->data;
    queue_items *tmp_ptr = first_ptr;

    first_ptr = first_ptr->next_ptr;

    delete tmp_ptr;
    tmp_ptr = NULL;

    return tmp;
}

void queue::print_all()
{
    queue_items *current_ptr = first_ptr;

    std::cout << "queue data : ";
    while (current_ptr != NULL) {
        std::cout << current_ptr->data << " -> ";
        current_ptr = current_ptr->next_ptr;
    }

    std::cout << "end." << std::endl;
}

int main()
{
    int i = 0, test_max = 10, intervals = 2;
    queue *q, *q2;

    try {
        q = queue::initialize(i);
        q2 = queue::initialize(i + 1);

        std::cout << "after initialize: " << std::endl;
        q->print_all();
        q2->print_all();

        std::cout << "\nstart test: " << std::endl;
        for(++i ;i < test_max; ++i) {
            q->enq(i);
            q2->enq(i * 2);
            if (i%intervals == 0) {
                std::cout << i << " => " << std::flush;
                q->print_all();
                std::cout << i << " => " << std::flush;
                q2->print_all();
            }
        }

        for(;i - 1 > 0; --i) {
            if (i%intervals == 0) {
                std::cout << i << " => ";
                q->print_all();
                std::cout << i << " => ";
                q2->print_all();
            }
            if (!q->is_empty()) {
                q->deq();
            }
            if (!q2->is_empty()) {
                q2->deq();
            }
        }

        std::cout << "end of test.\n" << std::endl;
        q->print_all();
        q2->print_all();

        delete q;
        delete q2;
    }
    catch (queue_exception& e) {
        std::cerr << "Exception: " <<  std::endl;
        std::cerr << "  -- " << e.message << std::endl;
        exit(8);
    }
    catch (...) {
        std::cerr << "Error: Unexpected exception occurred." << std::endl;
        exit(8);
    }

    return 0;
}
after initialize:
queue data : 0 -> end.
queue data : 1 -> end.

start test:
2 => queue data : 0 -> 1 -> 2 -> end.
2 => queue data : 1 -> 2 -> 4 -> end.
4 => queue data : 0 -> 1 -> 2 -> 3 -> 4 -> end.
4 => queue data : 1 -> 2 -> 4 -> 6 -> 8 -> end.
6 => queue data : 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> end.
6 => queue data : 1 -> 2 -> 4 -> 6 -> 8 -> 10 -> 12 -> end.
8 => queue data : 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> end.
8 => queue data : 1 -> 2 -> 4 -> 6 -> 8 -> 10 -> 12 -> 14 -> 16 -> end.
10 => queue data : 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> end.
10 => queue data : 1 -> 2 -> 4 -> 6 -> 8 -> 10 -> 12 -> 14 -> 16 -> 18 -> end.
8 => queue data : 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> end.
8 => queue data : 4 -> 6 -> 8 -> 10 -> 12 -> 14 -> 16 -> 18 -> end.
6 => queue data : 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> end.
6 => queue data : 8 -> 10 -> 12 -> 14 -> 16 -> 18 -> end.
4 => queue data : 6 -> 7 -> 8 -> 9 -> end.
4 => queue data : 12 -> 14 -> 16 -> 18 -> end.
2 => queue data : 8 -> 9 -> end.
2 => queue data : 16 -> 18 -> end.
end of test.

queue data : 9 -> end.
queue data : 18 -> end.

valgrind的にも.

% valgrind --leak-check=full ./a.out
==21772== Memcheck, a memory error detector.
==21772== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==21772== Using LibVEX rev 1658, a library for dynamic binary translation.
==21772== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==21772== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==21772== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==21772== For more details, rerun with: -v
==21772==
after initialize:
queue data : 0 -> end.
queue data : 1 -> end.

start test:
2 => queue data : 0 -> 1 -> 2 -> end.
2 => queue data : 1 -> 2 -> 4 -> end.
4 => queue data : 0 -> 1 -> 2 -> 3 -> 4 -> end.
4 => queue data : 1 -> 2 -> 4 -> 6 -> 8 -> end.
6 => queue data : 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> end.
6 => queue data : 1 -> 2 -> 4 -> 6 -> 8 -> 10 -> 12 -> end.
8 => queue data : 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> end.
8 => queue data : 1 -> 2 -> 4 -> 6 -> 8 -> 10 -> 12 -> 14 -> 16 -> end.
10 => queue data : 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> end.
10 => queue data : 1 -> 2 -> 4 -> 6 -> 8 -> 10 -> 12 -> 14 -> 16 -> 18 -> end.
8 => queue data : 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> end.
8 => queue data : 4 -> 6 -> 8 -> 10 -> 12 -> 14 -> 16 -> 18 -> end.
6 => queue data : 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> end.
6 => queue data : 8 -> 10 -> 12 -> 14 -> 16 -> 18 -> end.
4 => queue data : 6 -> 7 -> 8 -> 9 -> end.
4 => queue data : 12 -> 14 -> 16 -> 18 -> end.
2 => queue data : 8 -> 9 -> end.
2 => queue data : 16 -> 18 -> end.
end of test.

queue data : 9 -> end.
queue data : 18 -> end.
==21772==
==21772== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 1)
==21772== malloc/free: in use at exit: 0 bytes in 0 blocks.
==21772== malloc/free: 22 allocs, 22 frees, 176 bytes allocated.
==21772== For counts of detected errors, rerun with: -v
==21772== All heap blocks were freed -- no leaks are possible.


queueのデストラクタでqueue_itemsを消してやらないとメモリリークする.でも,デストラクタにちゃんとdeleteするコード書けば,mainをたとえば以下のようにしても,

int main()
{
    int i = 0, test_max = 10, intervals = 2;
    queue *q, *q2;

    try {
        q = queue::initialize(i);
        q2 = queue::initialize(i + 1);

        std::cout << "after initialize: " << std::endl;
        q->print_all();
        q2->print_all();

        std::cout << "\nstart test: " << std::endl;
        for(++i ;i < test_max; ++i) {
            q->enq(i);
            q2->enq(i * 2);
            if (i%intervals == 0) {
                std::cout << i << " => " << std::flush;
                //q->print_all(); // プリントは省略
                std::cout << i << " => " << std::flush;
                //q2->print_all();
            }
        }

        /* deq しない
        for(;i - 1 > 0; --i) {
            if (i%intervals == 0) {
                std::cout << i << " => ";
                q->print_all();
                std::cout << i << " => ";
                q2->print_all();
            }
            if (!q->is_empty()) {
                q->deq();
            }
            if (!q2->is_empty()) {
                q2->deq();
            }
        }
        */

        std::cout << "end of test.\n" << std::endl;
        q->print_all();
        q2->print_all();

        delete q;
        delete q2;
    }
    catch (queue_exception& e) {
        std::cerr << "Exception: " <<  std::endl;
        std::cerr << "  -- " << e.message << std::endl;
        exit(8);
    }
    catch (...) {
        std::cerr << "Error: Unexpected exception occurred." << std::endl;
        exit(8);
    }

    return 0;
}
% valgrind --leak-check=full ./a.out
==21861== Memcheck, a memory error detector.
==21861== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==21861== Using LibVEX rev 1658, a library for dynamic binary translation.
==21861== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==21861== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==21861== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==21861== For more details, rerun with: -v
==21861==
after initialize:
queue data : 0 -> end.
queue data : 1 -> end.

start test:
2 => 2 => 4 => 4 => 6 => 6 => 8 => 8 => end of test.

queue data : 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> end.
queue data : 1 -> 2 -> 4 -> 6 -> 8 -> 10 -> 12 -> 14 -> 16 -> 18 -> end.
==21861==
==21861== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 1)
==21861== malloc/free: in use at exit: 0 bytes in 0 blocks.
==21861== malloc/free: 22 allocs, 22 frees, 176 bytes allocated.
==21861== For counts of detected errors, rerun with: -v
==21861== All heap blocks were freed -- no leaks are possible.

ちゃんと開放される.
インスタンスのメンバのメモリ管理も自分の仕事.