001-01  前へ←  ホームへ  →次へ  001-03

No.001-02
   拡張リスト・クラスのテンプレート(ポインタ・リスト編)

前回のリスト構造XLIST定数をそのままリスト化するには非常に便利なのですが、
クラスをリスト化する場合には問題があり、
常にリストには引数のコピーであって引数そのものでない部分と、XLISTのdelete時に強制的にデストラクタが発生してしまうのです。
これの対策にはコピーコンストラクタをしっかり作ればいいのですが、毎回すべてのクラスに行うのは大変ですし、
第一、メモリの有効活用や、速度的なことを考えるならあまり良い方法ではありません。

そこで例えば class AAA のリストを作る場合
XLIST<AAA*> aaa_list;
として AAAのポインタでリスト化すればスッキリ解決です。
リストにはクラスのポインタが入ってるだけなのでデストラクタは発生しないのです。

XLIST<AAA*> aaa_list;
AAA *p_aaa;
p_aaa = new AAA;
aaa_list.push(p_aaa);
……
aaa_list.pop(n);
delete p_aaa;

まあこのまま使ってもいいんですが、本当にデストラクタが自動でないのも不便。
ついでにnew演算も自動化したいってコトで新テンプレートを作成。

PLIST(ポインタ・リスト)
自動でnew と delete する。ポインタのリスト。deleteしない設定も可能。
基本的にはXLIST<クラス名*>的な概念で形成し、それをちょっと拡張した感じ。

使い方はシンプル
PLIST<クラス名> 変数名;  ・・・宣言(内部でXLIST<クラス名*>を宣言している)
push(アイテムポインタ); ・・・アイテムへのポインタをリストに追加
a_push(void) ・・・内部でnew でメモリを確保し、そのポインタをリストに追加
pop(n); ・・・n番目のアイテムをリストから削除
変数名[n]; ・・・配列的にアクセス
size(); ・・・現在のアイテム数の取得

 plist.h

#ifndef _PLIST_H_
#define _PLIST_H_

#include <stdio.h>
#include <stdlib.h>
#include "xlist.h"

//==========================================
//      PLIST   ポインタ・リスト            
//==========================================
template <class T> class PLIST {
    char destruct_flag;
    XLIST<T*> xlist;    // has a型(多態push作成のためis aでない)
    public :

    // n1番目とn2番目のアイテムを交換する(swap)
    swap(int n1, int n2){
        T* tmp_t=xlist[n1];
        xlist[n1]=xlist[n2];
        xlist[n2]=tmp_t;
    };
    // 最後のアイテム(参照)を返す
    T* &last(){ return xlist.last(); };

    // アイテム数を返す(len, size で同じもの)
    len(){  return xlist.size(); };
    size(){ return xlist.size(); };

    // リサイズ
    resize(int n){
        int old_size=size();    // 旧サイズの保持
        int res=xlist.resize(n);    // メンバxlistでリサイズ実行
        int i;
        if (old_size<size()){
            for(i=old_size;i<size();i++) xlist[i]=a_push(); // 追加した分だけメモリ確保
        }

        return res;
    };

    // pop時アイテムのdeleteしないよう設定する
    set_no_destruct(){ return destruct_flag=0; }

    // コンストラクタ
    PLIST(){
        destruct_flag=1;    // pop時アイテムのdelete(アイテムのデストラクタが走る)
        T *t=NULL;          // デフォルト値はNULL
        xlist.set_default(t);   // デフォルト値はNULLであることをxlistに設定
    };

    // デストラクタ
    ~PLIST(){ del_all(); };

    // オート・プッシュ
    T *a_push(int n=-1){
        T* pt = new T;
        if (n==-1)  xlist.push(pt);     // n==-1ならアイテムは末尾に追加
        else        xlist.push(pt, n);  // n が範囲内ならアイテムはn番目に挿入

        // 返り値
        return (n==-1)? last() : xlist[n];
    }

    // アイテム追加(通常プッシュ)
    // 引数  t : 値、 n : 挿入位置
    T *push(T &t, int n=-1){
        T* pt = new T;
        *pt=t;
        if (n==-1)  xlist.push(pt);     // n==-1ならアイテムは末尾に追加
        else        xlist.push(pt, n);  // n が範囲内ならアイテムはn番目に挿入

        // 返り値
        return (n==-1)? last() : xlist[n];
    }

    // ポインタ引数でアイテム追加
    // 引数  t : 値、 n : 挿入位置
    p_push(T *t=NULL, int n=-1){
        if (!t) t = new T;
        if (n==-1) xlist.push(t);
        else        xlist.push(t, n);
        return 0;
    };

    // 第n番目のアイテム削除
    pop(int n=-1){
        if (destruct_flag) delete xlist[n];
        xlist[n]=NULL;
        xlist.pop(n);
        return 0;
    };

    // tの値と同じアイテムの削除
    val_pop(T *t){ return xlist.val_pop(t); }

    // ランダムアクセス
    T* &operator [](int n){ return xlist[n]; };

    // 第n1番目のアイテムを第n2番目に移動
    roll(int n1, int n2){ return xlist.roll(n1, n2); }

    // 全アイテム削除
    del_all(){
        int i, del_len=xlist.size();
        for(i=del_len-1;i>=0;i--) pop(i);
        return 0;
    }
};

#endif  // _PLIST_H_




リファレンス
【PLIST】      ポインタ・リスト構造
ポインタでリスト構造を組み立て、配列的アクセス時に各アイテムへのポインタが返るようにします。
不意のデストラクタを防ぎ、配列外アクセス時にはNULLが返るようになってます。
PLISTのデストラクタで各アイテムのデストラクタが呼び出されます
高速(ミリ秒単位)にpush系関数とpopを繰り返すとメモリの確保と開放が間にあわずリークやフリーズを引き起こすことがあります

汎用関数

・T *push(T &t, int n);
リストにアイテムを追加します
戻り値 新しいアイテムへのポインタを返します

リストのn番目の位置にアイテムを追加します
nを省略するか、またn==-1のとき追加位置はリスト末尾になります
追加されるアイテムは引数のコピーになります

・int p_push(T *t=NULL, int n=-1);
引数ポインタをリストに追加します
戻り値 必ず0が返ります

引数のポインタ(とその先の確保されてるメモリ)をリストのn番目の位置に追加します。
nを省略するか、またn==-1のとき追加位置はリスト末尾になります。
ポインタに確保するメモリは必ずnew演算子を使ってください(pop関数でddeleteを使用しているため)。
引数 *t ==NULLのとき関数内でメモリを確保します。

・T *a_push(int n=-1);
自動でリストにアイテムを追加します
戻り値 新しいアイテムへのポインタを返します

new演算子を使ってメモリ確保して、リストのn番目の位置にアイテムを追加します。
nを省略するか、またn==-1のとき追加位置はリスト末尾になります。

・pop(int n);
リストからアイテムを削除します
戻り値 新しいアイテム数を返します

リストのn番目のアイテムを削除します
nを省略するか、またn==-1のとき削除位置はリスト末尾になります

・val_pop(T *t);
リストからアイテムを削除します
戻り値 削除に成功したら1、削除するアイテムがなかったら0を返します

リスト内のアイテムで引数と同じポインタのアイテムを1つ削除します

・size();
リストのアイテムの数を取得します。
戻り値 アイテム数を返します

変数名[n];
配列的にアクセスします
戻り値 n番目のアイテムのポインタへの参照

リストのn番目のアイテムのポインタを参照します。じかに代入もできますもできますが直代入はお奨めしません。

・del_all();
           (XLIST版と同じ)
アイテムをすべて削除します
戻り値 必ず0が返ります

リストのアイテム全てを削除します。
各アイテムのデストラクタも自動で呼ばれます

・roll(int n1, int n2);
           (XLIST版と同じ)
第n1番目のアイテムを第n2番目に移動します
戻り値 アイテム数を返します


例:1番目のアイテムを末尾に移動したりすると2番目以降の順番が全て繰り上がり、2番目のアイテムが先頭になります

・swap(int n1, int n2)
           (XLIST版と同じ)
リストのn1番目とn2番目を入れ替えます
戻り値 必ず0が返ります

set_no_destruct();
pop時アイテムのdeleteしない
戻り値 必ず0が返ります

popする時(アイテムをリストから除外するとき)、deleteを呼ばないように設定します。

・resize(int n);
アイテム数を強制的にn個に変更します
戻り値 アイテム数を返します

変更後のアイテム数が変更前のアイテム数より小さければければその分のアイテムは削除されます
変更後のアイテム数が変更前のアイテム数より大きければければその分のアイテムはメモリ確保されます。

●PLIST サンプル

#include "plist.h"

int main(){
    PLIST<int> list;    // int型のポインタ・リストを宣言
    int n=100, *pn;
    pn=list.a_push();   // アイテムを追加しそのアイテムへのポインタを得る
    *pn=n++;            // 追加したアイテムに値を代入
    pn=list.a_push();*pn=n++;
    pn=list.a_push();*pn=n++;
    pn=list.a_push();*pn=n++;
    pn=list.a_push();*pn=n++;
    pn=list.a_push();*pn=n++;
    list.pop(3);                                // list[3]をリストから削除
    for(int i=0;i<list.size();i++){
        printf("list[%d]=%d\n", i, *list[i]);   // list[i]を表示
    }
    printf("list.size(); %d\n", list.size());   // リストアイテム数を表示

    list.del_all();     // アイテムの全削除。
    printf("list.del_all();呼び出し \n");

    printf("list.size(); %d\n", list.size());   // リストアイテム数を表示
    list.resize(4);                             // アイテムの数を4個にする
    printf("list.size(); %d\n", list.size());   // リストアイテム数を表示
    return 0;
}
実行結果

●PLIST サンプル2


#include "plist.h"
#include <string>

class AAA{
    public:
    char *m_name;
    AAA(){
        m_name=NULL;
    }
    ~AAA(){
        if (m_name) delete[] m_name;
    }
    void cpy(char *str){
        if (!str) return;
        m_name = new char[strlen(str)+1];
        strcpy(m_name, str);
    }
};

int main(){
    int n=100;
    PLIST<AAA> aaa_list;    // AAA型のポインタ・リストを宣言
    AAA *p_aaa;
    p_aaa=aaa_list.a_push();    // アイテムを追加しそのアイテムへのポインタを得る
    p_aaa->cpy("アルファベット");           // 追加したアイテムに値を代入
    p_aaa=aaa_list.a_push();    p_aaa->cpy("AB");
    p_aaa=aaa_list.a_push();    p_aaa->cpy("CDE");
    p_aaa=aaa_list.a_push();    p_aaa->cpy("FGHI");
    p_aaa=aaa_list.a_push();    p_aaa->cpy("JKLMN");
    p_aaa = new AAA;        // 自分で new 演算してもいい。
    aaa_list.p_push(p_aaa); p_aaa->cpy("OPQR"); // 自分でnewした時は a_push でなく p_push
    p_aaa=aaa_list.a_push();    p_aaa->cpy("STU");
    p_aaa=aaa_list.a_push();    p_aaa->cpy("VW");
    p_aaa=aaa_list.a_push();    p_aaa->cpy("XYZ");

    aaa_list.pop(2);        // aaa_list[2] をリストから削除
    aaa_list.pop();         // 末尾アイテムをリストから削除
    for(int i=0;i<aaa_list.size();i++){
        printf("aaa_list[%d]->m_name=%s\n", i, aaa_list[i]->m_name);    // list[i]を表示
    }

    printf("aaa_list.size(); %d\n", aaa_list.size());   // リストアイテム数を表示
    aaa_list.del_all();                                 // アイテムの全削除、ただしメモリは解放しない。

    printf("aaa_list.del_all();呼び出し \n");
    printf("aaa_list.size(); %d\n", aaa_list.size());   // リストアイテム数を表示

    aaa_list.resize(4);                                 // アイテムの数を4個にする
    printf("aaa_list.size(); %d\n", aaa_list.size());   // リストアイテム数を表示
    return 0;
}
実行結果


上記ソースは全て自由に改編して使ってかまいませんが必ず自己責任でね。  

 001-01  前へ←  ホームへ  →次へ  001-02