.順調に遅れております。 .あらすじ .これが JNR ホテル内部だ!: .結局 40 分ほど遅れ: .起きたら仙台手前。1h10m 遅れ。どうもその後、雨の影響でさらに遅れ、 仙台のラッシュアワーに巻き込まれている模様。 .食堂車でいつもの洋朝食 1600 円也: .郡山 950 発車。1h23m 遅れ。 .結局 1h30m くらい遅れて上野に到着。 |
.今回は旅行に出てから 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 だったからといって、 たとえば NetBSD ユーザがこの本を買わないかというと全くそんなことはないし、 むしろ NetBSD ユーザのほうがこういう本を好んで買う気質がありそうな気がする :-) .それにしても NetBSD 本が欲しいなあ。 |
.「青色図書館 / 林 みかせ」を読んで寝た。 |
.いつもの 741M で西へ。いま熱海。 .だいたい経路は決まってて、今日は高山泊まりだけど、 明日は天気しだいで白川郷に抜けるか神岡に抜けるか。 いずれにしても帰りは金沢から北陸号 B1。 .浜松で鰻丼食って、新快速で大垣まで来た。 .美濃赤坂に寄って、いま岐阜で高山本線にゲリロン。 高山まで三時間ちょっとかかるぜ。 .ローカル線とは言ってもなかなかの輸送密度があるので、 所要時間三時間のうち三十分くらいは交換待ち。 ほとんど全駅待避可能で、駅以外にちらほらと信号所があるのだけれど、 地形が厳しいところで延々と単線が続くので、 そういうところがどうしてもボトルネックになる。 .もう日が暮れて景色は全然見えなかったけれど、 それを差し引いたとしても山岳路線の醍醐味があっていい線だと思う。 今度は明るい時間に来よう。 .高山泊。ホテルは可もなく不可もなく。ただ、客筋があまりよろしくなさげ。 まあ、ハイシーズンのメジャーな観光地はどうしてもそうなる。 客は宿を選べるが、宿は客を選べないし、客は宿の客筋を選べない。 止んぬる哉止んぬる哉。 .恒例の運賃計算。武蔵溝ノ口→高山で 527.2 営業キロ 8510 円。 岐阜⇔美濃赤坂 18.7 営業キロ往復 640 円。計 9150 円。 .明日は晴れそうなので白川郷で 2 時間くらいふらふらした後 (丁度どぶろく祭りの時季なのよねん)、 城端に抜けようと思う。富山の三枝線を処理して金沢に出る。 運賃合計 3000 円くらいなので微妙に乗れてないけれど、 元は今日まででもう取れてるのでよし。 .しかし、帰りの北陸号 B1 の金沢→上野は運賃料金全部込みで 17110 円か。 高いなぁというべきか、北陸フリーって安すぎるなぁというべきか。 富山は改めてくることにして、今回のところは北アルプスを松本の方に抜けて、 中央線鈍行ないしはホリデー快速で戻ってきてもいいんだけどねぇ。 ただどうも、行くと思ったときに行っとかないと、 結局富山港線乗らずじまいになりそうではある。 |
.上野。サンディーヌエクスプレスって 6:30 から開いてるんだね。 .普通に仕事。早めに撤収。 .「メタモ・キス(3) / おもて 空良」を読んで寝た。 まあネタも絵も好きなんですけど。 おいしいネタの提示だけで終始してしまったようなところもあるので、 ストーリー漫画としてはいまひとつ。 次回作はもうちょっと話を練ったほうがよさげ。 |
.「アニマル横町(6) / 前川 涼」を半分くらい読んで寝た。 アニメは見てないけど、どうも評価は真っ二つみたいやね。 まあ漫画自体がそういう漫画だ。 |
.CP932 の完全対応については、 テストしていただいたり 、 パッチ作っていただいたり したおかげで current では直ったわけですが (PR の編集と pull-up request かけとかないといかんな)、 新たに ISO-2022-JP の問題なんてものが。 .Citrus iconv は内部で一旦 wchar に変更し、 これを csid/index ペアというのに分解するようになっているのだけれど、 mb→wc 変換で mbrtowc 相当の関数を使っているのが問題に。 .mbrtowc は、 エラーではないけど入力文字が不完全だったりして wc を返せない場合には、 特殊なリターン値である (size_t)-2 を返すことになってるのだけれども、 ISO-2022 では
.安易な解決策は、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() のセマンティックが変わっても 実質的に影響がないのでリネームする必要がない。 この方法の欠点は、どんな値をセットするのがいいのか判然としないことだなぁ。 |
.しかしながら、mbrtowc() と同等のインターフェースを使うことによる弊害はこれ以外にもあって、 .どうも、「新しい mb→wc 変換関数」と「新しいステート取得関数」 の二つを用意するのがいいような気がしてきた。 mbrtowc() の (size_t)-2 には「なんで wchar が返せないのか」 という理由づけがしてあるけど、本質的にはそれは余計なことであって、
.こんな感じかなぁ(関数名は仮): .使い方: .コンセプトとしてはこれでいいんじゃないかという気がしてきた。 .問題は……これ 3.0 に pullup できるのかなぁ。 .って、wcrtomb_priv() って NUL 扱えるんじゃん。俺も忘れてたよ(ぉ。 まあこれもあまり良いインターフェースではないので、 将来的にはこっちも fetch_wchar(仮) みたいなのですっきりさせるとして、 とりあえずは get_state(仮) の方を実装するんですかね。 .熊谷さんからお手紙来たので転載: まあ mbrtowc() としては致し方もない部分があるのは確かですな。 熊谷さんにはメールで返事を出しておいたけれども、 DR#288 というのは これ 。 .ちなみに、mbrtowc() の範囲ならば、 「マルチバイト文字列」の定義から、 「\0 を食わせてみる」という手で尻切れトンボかどうかは判る。 \0 は常に NUL なので、 もし文字/シフトシーケンスの途中なら、EILSEQ が返ってくることが期待できる。 もっとも、ちゃんとそこまで意識してあるプログラムは見たことがないし、 iconv() のバックエンドではやっぱり使えないけど。 |
.The X.Org Foundation X11R6.9/X11R7.0 Release Plan 。 R6.9 と R7.0 は実質的に同じものだが、 ソースの構造が違うらしい。R7.0 は autoconf 化なんかがされてる。 .気になるところをピックアップ。
|