某日記

(中期)

平成17年10月11日(火曜日)

その後

順調に遅れております。

あらすじ
函館駅に戻った小鳥ちゃん(仮称)を待っていたのは列車が遅れるという 知らせであった。JNR ホテル出動! などの騒ぎを遠目に見つつ、 駅構内のベンチで立ったり座ったりしていたら、足を蚊に食われた。 そのうち駅員がやってきて 「北斗星も遅れるので、JNR ホテルでご休憩でもいかがですか」 とナンパされ、もじもじしながらホテルに入る小鳥ちゃん(仮称)なのであった。

これが JNR ホテル内部だ!:

結局 40 分ほど遅れ:

起きたら仙台手前。1h10m 遅れ。どうもその後、雨の影響でさらに遅れ、 仙台のラッシュアワーに巻き込まれている模様。

食堂車でいつもの洋朝食 1600 円也:

郡山 950 発車。1h23m 遅れ。

結局 1h30m くらい遅れて上野に到着。

平成17年10月12日(水曜日)

昨日

そのまま出社して、引っ越しの後始末など。 都落ち感あふれる状況ではあるものの、 まあ普通のオフィス環境になっただけという考え方もできる。

帰ってばたんきゅー。

今日

喉が痛い。

今回の行程

今回は旅行に出てから 10/9, 10/10 の行程を決めた。

10/8 東京 - 米沢 - 山形 - 左沢 - 山形 - 仙台 - 利府 - 仙台 - 八戸

山形新幹線自由席は結構並んでいたが、 定期と臨時が 6 分で続行しているところを選んだので通路側に座れた。 寝て起きたら峠をこえて米沢の方に下りはじめたところだった。 牛肉どまんなかを買うためだけに米沢で途中下車。 左沢線は車両の塗色がユニーク(婉曲表現)だと思う。 沿線はあまり面白くない。仙山線は、面白山高原で降りてナンボという気もする。 まだ全然紅葉してなかった。 せっかく仙台に来たので、ついでに利府支線に乗ってから八戸でやあ 3 と合流。

10/9 八戸 - 盛岡 - 花巻 - 北上 - ゆだ錦秋湖 - 横手 - 秋田 - 男鹿 - 秋田 - 青森

せっかくだから北上線でも乗るかと思って時刻表見たら、 10/9 ピンポイントで「湯煙リレー号」というのが走るようなので、 乗ってみた。義経がらみの SL イベント列車とのタイアップの模様。 国鉄色キハ 58 二連なんてもんを使うから、 係員の不手際もあってアレなことになっていたけど、 座席に全員座れる程度の混雑。 横手からは奥羽線のロングシート。ちょうど昼時なので、 なぜか盛岡で売っていた八戸小唄寿司を食った。 男鹿線は、地図だと海が見えそうなのに全然見えないので、あまり面白くはない。 普通列車のくせに気動車チャイムを鳴らすのは珍しかった。 かもしかで青森。 盛岡では「あぶり〆鯖の田楽寿し」も仕入れてあったので、晩酌。

10/10 青森 - 蟹田 - 三厩 - 蟹田 - 木古内 - 江差 - 木古内 - 函館 - 上野

津軽線は紅葉の時期にくるとそれなりに楽しめるかもしれないが、 まあ積極的にくるほどのこともなさげではある。 短いながらも峠も越えるし最後に海も見える、凝縮した路線。 江差線も同様。江差線くらいの緯度になると、さすがに紅葉が始まってた。 函館はひどい雨だったので、タクシープレイで谷地頭温泉。片道 1000 円ほど。

参照とポインタ

この話 。 わたくし根が古いせいかもしれないが、 どうも参照は好きになれんですたい。 これは要するに、 「呼び出し側の字面を見ても、値渡しと参照渡しの区別がつかない」 という一点に尽きる。 だから、件のケースだったら

void
SomeFunc( std::vector<CSomeClass>* a_vec )
{
	std::vector<CSomeClass>& vec = *a_vec;
	...
}
とでもしてしまう。そもそも、 放っておくと参照渡しになってしまうような言語も好きではないのであって、 とどのつまり参照渡しでも呼び出し側に明示的な & が必要な言語がほしい。

もうちょっと詳しく言えば、 ポインタ渡しや参照渡しというのは二つの狙いがあるわけです。つまり、 純粋にコピーのオーバーヘッドを嫌っている場合と、 引数に対する副作用を呼び出し元に伝搬させたい場合。 前者のケースでは暗黙のうちに参照渡しになってくれたほうが むしろ嬉しいのだが、 後者のケースでは呼び出し側でもコンベンションとしてそれを明示したい。 いずれにしても、ポインタのほうが盲目的に良いと思っているわけではない。

で、「参照はポインタ嫌いが使うもの」という話ですが、 C でポインタを使うような場面というのは、 C に固有な事情であることも多いので、 C++ でそういうケースを扱う場合に単純に参照を使えばよいというものでもない、 ということは注目に値すると思う。

いろんなケースを見ていこう。 C ではデータのコピーを発生させたくない場合にポインタを使うことがある。 次のようなコードはこの典型的な例:


こういうケースの場合、C++ ではconst & の出番ですな (「Point クラスのメソッドにすればいい」「<< をオーバライドすればいい」 というのはひとまず置いとく)、 こういうところであえてポインタを使う必要はない。 これに限って言えば、 わざわざ呼び出し元で & をつけなきゃならない C のほうが嫌だ。 

なお、インライン関数ではだいたい最適化されるので、 型とか気にせず常に const & を使ってしまってもあまり問題にはならない。 値渡しとの違いは引数変数の内容を書き換えることができないということだが、 だいたいにおいて、値渡しされた引数変数の内容を書き換えるというのも、 あまり行儀の良いことではないという考え方もあろう。

C++ の参照の第一原則: 「使える場面では const & を使おう」

つぎ。値を返すような場面で C のポインタと同じように参照を使うのは だいたい間違ってると思ってよい。 これは「引数に対する副作用を呼び出し元に伝搬させたい場合」 の一つに相当するのだけれども、 たとえば、次のような C のコードはありがちなものですな:

void
point_get(const Point *p, int *x, int *y)
{
	*x = p->x;
	*y = p->y;
}
これを呼び出すコードは、

となる。 

これと全く同じ発想で、次のように参照を使うのは全く良くない:

class Point
{
	int m_x_, m_y_;
...
public:
	void
	get(int &x, int &y) const
	{
		x = m_x_;
		y = m_y_;
	}
};
これを呼び出すコードは

となるけれど、気持ち悪さがかなり増した気がする。 

これは好みの問題だけではない。そもそも元のコードもあまり良くはない。 純粋にインターフェースだけを論じるならば、 一つの関数が複数の値を返すようなインターフェースはあまり良くないことが多い。 それにもかかわらず、なぜ C でこういうインターフェースにするかというと、 「関数呼び出しのオーバーヘッドをなるべく避けたい」 という実装寄りの考えに引きずられてることが多い。 C++ ならばインライン関数にすればいいだけの場面が多いので、むしろ

class Point
{
	int m_x_, m_y_;
...
public:
	int x() const { return m_x_; }
	int y() const { return m_y_; }
};
とすべきなのである。

ところで、こういう単純なケースならいいけれど、もっと複雑なケースもある。 たとえば、複雑な継承が行われることがわかってるウィンドウの オブジェクトからジオメトリを取り出すメソッド:

class Window {
public:
	virtual void get_geometry(int *x, int *y, int *w, int *h) = 0;
};
なんてのはインライン関数にできない。でもこういうような場合は、
class Rect
{
	int m_x_, m_y_, m_w_, m_h_;
public:
	int x() const { return m_x_; }
	int y() const { return m_y_; }
	int w() const { return m_w_; }
	int h() const { return m_h_; }
....
};
などというヘルパーを用意しといて、
	virtual Rect get_geometry() = 0;
とかすると、やっぱり値を一つだけ返せばよくなる (余談だけど、 こういうヘルパーを単純な構造体ではなくクラスにするべきかどうかというのも議論の余地がありそうだ --- だって、上みたいにいちいちアクセサメソッド書くの面倒くさいじゃん。一方で、メソッドにしておくと潰しが効くというメリットもある)。

参照の第二原則: 「値を返すために参照を使うのは良くない。ポインタにしても駄目だけど」

最後に、 「引数に対する副作用を呼び出し元に伝搬させたい場合」 のもう一つのケースとして、 オブジェクトの状態変更を伝搬させる目的でポインタが使われているような 場面というのがあるけれども、 これを C++ でポインタ渡しにするか参照渡しにするかは一長一短がある。 しかしながら、たとえば C で

void
point_set_x(Point *p, int x)
{
	p->x = x;
}
としているようなケースは、 C++ では単純なメソッド呼び出しにすればいいだけなので、 半分くらいはポインタも参照も不要になる。一方で、 次のようなケースはどうだろう:
void
point_read_from_stream(Point *p, FILE *fp)
{
	fscanf(fp, "%d %d", &p->x, &p->y);
}
これを C++ の参照渡しを使って書き直せば (「>>をオーバライドすればいい」というのは置いとく --- わたしゃ演算子オーバライドも嫌いだし、 iostream におけるそれは braindamaged だと思ってるけど)、
void
Point::read_from_stream(std::istream &is)
{
	is >> m_x_ >> m_y_;
}
となり、ポインタ渡しなら
void
Point::read_from_stream(std::istream *is)
{
	*is >> m_x_ >> m_y_;
}
となる。*is がキモかったら
void
Point::read_from_stream(std::istream *a_is)
{
	std::istream &is = *a_is;
	is >> m_x_ >> m_y_;
}
とする。 参照渡しは書き方が簡潔になるし、 ジェネリックプログラミングでは威力を発揮するというメリットがあるのに対し、 ポインタ渡しは、 呼び出し側の字面から何らかの副作用があることが明確にわかる。

私はこういう場合にはだいたいポインタ渡しのメリットの方を好むのだが、 ただそれも、参照渡しとポインタ渡しを適切に使い分けているという前提が あって初めて有効なのだとも言える。 コピーのオーバーヘッドを嫌っている場合にもポインタを 使ってしまっていたりすると、その効果が半減してしまう。

まあ、C++ の参照というのはいまいち中途半端感が 拭えないようなところもあるので、癖を見切ってうまく使ってください。

FreeBSD 本

めでたい 。 でも、やっぱりタイトルは微妙だと思うなぁ。 「 タイトルで FreeBSD ユーザ以外には関係ないと思われるのは 惜しいと思ったからです 」 と言うけれど、タイトルが FreeBSD だったからといって、 たとえば NetBSD ユーザがこの本を買わないかというと全くそんなことはないし、 むしろ NetBSD ユーザのほうがこういう本を好んで買う気質がありそうな気がする :-)

それにしても NetBSD 本が欲しいなあ。

平成17年10月14日(金曜日)

昨日

青色図書館 / 林 みかせ」を読んで寝た。

平成17年10月15日(土曜日)

昨日

LaLa DX を半分くらい読んで寝た。

今日

いつもの 741M で西へ。いま熱海。

だいたい経路は決まってて、今日は高山泊まりだけど、 明日は天気しだいで白川郷に抜けるか神岡に抜けるか。 いずれにしても帰りは金沢から北陸号 B1。

浜松で鰻丼食って、新快速で大垣まで来た。

美濃赤坂に寄って、いま岐阜で高山本線にゲリロン。 高山まで三時間ちょっとかかるぜ。

ローカル線とは言ってもなかなかの輸送密度があるので、 所要時間三時間のうち三十分くらいは交換待ち。 ほとんど全駅待避可能で、駅以外にちらほらと信号所があるのだけれど、 地形が厳しいところで延々と単線が続くので、 そういうところがどうしてもボトルネックになる。

もう日が暮れて景色は全然見えなかったけれど、 それを差し引いたとしても山岳路線の醍醐味があっていい線だと思う。 今度は明るい時間に来よう。

高山泊。ホテルは可もなく不可もなく。ただ、客筋があまりよろしくなさげ。 まあ、ハイシーズンのメジャーな観光地はどうしてもそうなる。 客は宿を選べるが、宿は客を選べないし、客は宿の客筋を選べない。 止んぬる哉止んぬる哉。

恒例の運賃計算。武蔵溝ノ口→高山で 527.2 営業キロ 8510 円。 岐阜⇔美濃赤坂 18.7 営業キロ往復 640 円。計 9150 円。

明日は晴れそうなので白川郷で 2 時間くらいふらふらした後 (丁度どぶろく祭りの時季なのよねん)、 城端に抜けようと思う。富山の三枝線を処理して金沢に出る。 運賃合計 3000 円くらいなので微妙に乗れてないけれど、 元は今日まででもう取れてるのでよし。

しかし、帰りの北陸号 B1 の金沢→上野は運賃料金全部込みで 17110 円か。 高いなぁというべきか、北陸フリーって安すぎるなぁというべきか。 富山は改めてくることにして、今回のところは北アルプスを松本の方に抜けて、 中央線鈍行ないしはホリデー快速で戻ってきてもいいんだけどねぇ。 ただどうも、行くと思ったときに行っとかないと、 結局富山港線乗らずじまいになりそうではある。

平成17年10月18日(火曜日)

日曜

高山からバスで白川郷→城端と抜けて、 城端→高岡→氷見→高岡→富山→岩瀬浜→富山→金沢。 金沢で飯食って銭湯寄って、北陸号で戻ってきた。

昨日

上野。サンディーヌエクスプレスって 6:30 から開いてるんだね。

普通に仕事。早めに撤収。

メタモ・キス(3) / おもて 空良」を読んで寝た。 まあネタも絵も好きなんですけど。 おいしいネタの提示だけで終始してしまったようなところもあるので、 ストーリー漫画としてはいまひとつ。 次回作はもうちょっと話を練ったほうがよさげ。

平成17年10月19日(水曜日)

昨日

アニマル横町(6) / 前川 涼」を半分くらい読んで寝た。 アニメは見てないけど、どうも評価は真っ二つみたいやね。 まあ漫画自体がそういう漫画だ。

Citrus iconv 問題

CP932 の完全対応については、 テストしていただいたり パッチ作っていただいたり したおかげで current では直ったわけですが (PR の編集と pull-up request かけとかないといかんな)、 新たに ISO-2022-JP の問題なんてものが。

Citrus iconv は内部で一旦 wchar に変更し、 これを csid/index ペアというのに分解するようになっているのだけれど、 mb→wc 変換で mbrtowc 相当の関数を使っているのが問題に。

mbrtowc は、 エラーではないけど入力文字が不完全だったりして wc を返せない場合には、 特殊なリターン値である (size_t)-2 を返すことになってるのだけれども、 ISO-2022 では

  1. 文字の途中で入力バッファが終わっている
  2. 文字は無く、シフトシーケンスの途中で入力バッファが終わっている
  3. バッファに完全なシフトシーケンスだけしかない
という場合が相当する。このうち、 1 と 2 は同様のケースだからいいとしても、 これらと 3 を区別できないのは困る。 実際、mbrtowc 単体としても 3 を区別できない現在の仕様では困るんだけど、 特に iconv(3) のバックエンドとして使う場合にはクリティカルに困る。 なぜなら、 「The string pointed to by *src terminates with an incomplete character or shift sequence.」な時、つまり 1 と 2 の時には EINVAL をセットしないといけないのだが、 3 の時はこれに該当しないのでエラーにできない。 どうしても 3 だけは区別できないと困る。

安易な解決策は、3 のようなケースでは mb→csid/index 変換関数である _citrus_stdenc_mbtocs() が nresult として (size_t)-3 を返すような仕様にするという方法だけれども、これはどうも嫌よねん。

本来は (size_t)-2 なんてものも微妙にナンセンスで、 これらは result status として errno 相当に返すのが正しいような気もするのだが……。 誰か、何かよいアイディアがあったら教えてください。

なんか (size_t)-3 にしちゃうのが一番厄介が少ないような気もしてきた。 あるいは、(size_t)-1 を返しておいて errno 相当は 0 にするか。 _citrus_stdenc_mbtocs() に関しては、 ops テーブルには古いのを残しておかないとバイナリ互換が崩れてしまうので、 実質的な rename になると思うのだけれども、 次に似たような瑕疵が見つかったときに、 今度は (size_t)-4 を導入してまた rename する、 なんてことをやるのは馬鹿らしいので、何とかしたいところ。 (size_t)-10 くらいまで予約しといて、 caller が知らない値を返された時は単純に EINVAL ではじくようにでもするか。 嫌だなぁ。 まあ、入力バッファサイズ以上の nresult が返されたら EINVAL にするという仕様でもいいのかな。

いずれにしても mbrtowc() そのものは仕様を変えるわけにもいかず壊れたままだけど。 Solaris が ISO C の LC_CTYPE まわりの関数で stateful なエンコーディングの取り扱いを諦めてしまったのは、 こういったあたりの事情なのかもしれず。

(size_t)-2 を返しておいて、適当な値を errno 相当にセットする、 という方法もあるな。 この方法だと、_citrus_stdenc_mbtocs() のセマンティックが変わっても 実質的に影響がないのでリネームする必要がない。 この方法の欠点は、どんな値をセットするのがいいのか判然としないことだなぁ。

平成17年10月20日(木曜日)

昨日

さっさと寝た。

ISO-2022

なるほど 。 mbstate_t はすべてを知っている。

しかしながら、mbrtowc() と同等のインターフェースを使うことによる弊害はこれ以外にもあって、 yamt さんの言うように「NUL 文字の長さがわからん」とか 、 DR#288 みたいな話もあるので、 こっちにも別のインターフェースが必要なのは確か。

どうも、「新しい mb→wc 変換関数」と「新しいステート取得関数」 の二つを用意するのがいいような気がしてきた。 mbrtowc() の (size_t)-2 には「なんで wchar が返せないのか」 という理由づけがしてあるけど、本質的にはそれは余計なことであって、

  • 文字を返した
  • 文字を返さなかった
  • エラー
の 3 つの状態さえ判別できれば十分であるような気がする。 「文字を返さなかった」時に、 なんで文字を返さなかったのかという理由は mbstate_t を見れば判るはずなので (あるいは判るように実装するという仕様にする)、 それはステート取得関数で取れるようにする。

こんな感じかなぁ(関数名は仮):


使い方:


コンセプトとしてはこれでいいんじゃないかという気がしてきた。

問題は……これ 3.0 に pullup できるのかなぁ。

って、wcrtomb_priv() って NUL 扱えるんじゃん。俺も忘れてたよ(ぉ。 まあこれもあまり良いインターフェースではないので、 将来的にはこっちも fetch_wchar(仮) みたいなのですっきりさせるとして、 とりあえずは get_state(仮) の方を実装するんですかね。

熊谷さんからお手紙来たので転載:


まあ mbrtowc() としては致し方もない部分があるのは確かですな。 熊谷さんにはメールで返事を出しておいたけれども、 DR#288 というのは これ 

ちなみに、mbrtowc() の範囲ならば、 「マルチバイト文字列」の定義から、 「\0 を食わせてみる」という手で尻切れトンボかどうかは判る。 \0 は常に NUL なので、 もし文字/シフトシーケンスの途中なら、EILSEQ が返ってくることが期待できる。 もっとも、ちゃんとそこまで意識してあるプログラムは見たことがないし、 iconv() のバックエンドではやっぱり使えないけど。

X11R6.9/R7

The X.Org Foundation X11R6.9/X11R7.0 Release Plan 。 R6.9 と R7.0 は実質的に同じものだが、 ソースの構造が違うらしい。R7.0 は autoconf 化なんかがされてる。

気になるところをピックアップ。

  • More support for enhanced visuals like 12-bit PseudoColor and 30-bit TrueColor - めんどくせぇ。
  • Improved ProPolice support - こういうのはいいね。
  • Switched to libdl-based module loader - 失われた 10 年って感じでいいね。
  • Output-only windows - 何だろう。
  • Non-rectangular mergedfb desktops - 何だろう。
  • Multiseat support - 何だろう。
  • Shared libraries now built for libXau & libXdmcp - 必要?

gigalandisk

再燃したので考えよう。

シリアルはやっぱり 3.3V ロジックなので、例によって ADM3202 か MAX3232 でドライブするとして、ピンアサインは ここ 。 必要なもの :

  • ADM3202 or MAX 3232 と 0.1uF のコンデンサ 5 個
  • D-SUB 9 ピンメスコネクタつきケーブル
  • ワイヤー若干量