g_list_foreach

STL(C++) の std::list と GLib の GList で foreach してみた。
C と C++ の微妙な違いがあってなかなか興味深い。

C++, STL

#include <iostream>
#include <list>
#include <algorithm>

void
show_data(std::string s) {
    std::cout << s << std::endl;
}

int
main (int argc, char **argv) {

    std::list<std::string> l;
    std::string s;

    for (int i=0; i<3; i++) {
        std::cout << "input " << i << " : ";
        std::cin >> s;
        l.push_back(s);
    }
    // for_each @ algorithm
    std::for_each(l.begin(), l.end(), show_data);
    return 0;
}

GLib

#include <glib.h>

void 
show_data(gpointer data ,gpointer user_data) {
    g_printf("%s\n",data);
}

void 
delete_data(gpointer data ,gpointer user_data) {
    g_free(data);
    data = NULL;
}

int
main (int argc, char **argv) {

    GList* list = NULL;
    gchar s[256];
    gint i;

    for (i=0; i<3; i++) {
        g_printf("input %d : ", i);
        scanf("%s", s);
        //list = g_list_append (list, s); // All Last Data
        list = g_list_append (list, g_strdup(s));
    }
    /* foreach */
    g_list_foreach(list, show_data, NULL);
    /* free */
    g_list_foreach(list, delete_data, NULL);
    g_list_free( list );
    return 0;
}

ビルド結果は同じものが作られるはず。

glist

std::for_each, g_list_foreach 共に関数ポインタを使っている。
GLib はソックリにしようと思ったのでしょうか?
STL は関数オブジェクトが使えるとかもろもろは置いておいて。

ところで for 文等を使わずにズラズラ並べるなら当然下記でもいい。
スタックのメモリ領域なので当然破棄処理も不要。
実際のアプリケーションでこんなコードになることはまずありえないですが。

list = g_list_append (list, "YAMAHA");
list = g_list_append (list, "HONDA");

for 文でコレをやると当然だけど全部同じ s ポインタを参照になる。
なのでデータを拾う毎にヒープに領域を作ってそのポインタを入れていく必要あり。
当然破棄も必須、C++ の std::string は全自動でやってくれているだけだし。

ただ知ってのとおり std::list は整数による添字アクセスができない。
というか何をするにもループ必須で正直使い勝手がよくない。
GList は一応こんなことができるようです。

gchar* c;
/* 3 番目を表示 */
c = (gchar*)g_list_nth_data(list, 2);
g_printf("%s\n", c);
/* 3 番目を削除 */
c = (gchar*)g_list_nth_data(list, 2);
list = g_list_remove(list, c);

STL を少し知っているなら直感的に書くことが可能、かつちょっぴり便利。
でも class は使えないからデストラクタで破棄とかはできないよってか。
むりやり std::list と同じにしようとしたのではないようで面白い。