December 23, 2006
[出来事] ファイルシステム破壊
やってしまいました.GNU Parted 1.7.1 + libreiserfs (progsreiserfs 0.3.0) でパーティションのサイズを変更しようとして... 以下のような今日の小咄 2003年12月分の記述と同様のエラーが発生してしまいました.具体的な残り時間や node 番号は失念したため,ここでは xxxx で示しています.
shrinking... 12% (time left xxx:xx) Error: Invalid node detected (xxxxxx). Unkonwn type.
ファイルシステムは破壊され,マウントできなくなってしまいました.reiserfsck --fix-fixable もダメもとで試しましたが,やはりダメでした.仕方なく最終手段の reiserfsck --rebuild-tree を実行することに.
実行後,居場所を失ったファイルやディレクトリが lost+found ディレクトリに大量移動してきました.その総容量,約 576MBytes.本当に消えて困るデータは別マシンにバックアップしていたのでいいのですが,Gentoo Linux の再インストールを今やるのは大変です.
幸い,/etc, /usr, /bin, /var は難を逃れたようです(もちろん完全に逃れたとは思えませんが...).そこで,これらも別なマシンにバックアップし,バックアップが完了し次第,パーティションを切り直してファイルシステムを再構築後,ファイルを元に戻し,システムを復帰させることにします.
新ルートパーティションに退避したデータをコピーして,GRUB の設定や /etc/fstab の書き換えを行った後,マシンを再起動すると... 問題なくGDM のログイン画面まで到達しました.
いざログインしようとすると,KDE が起動しません.
% kdeinit kdeinit: symbol lookup error: /usr/kde/3.5/lib/libkdecore.so.4: undefined symbol: (xx) %
(xx) で書いたところは文字化けして読めませんでした.シンボル名が文字化けしてるということは... 一見,難を逃れたように見えるファイルはやはりダメージを受けているということになります.
KDE 関連は怪しいので,kdebase と kdelibs を入れ直してみようとするも,今度は Perl のファイルが見つからない(lost+found へ行ってしまったのでしょう)とのことで,Automake が起動しません.よって perl も再インストールします.
perl が入ったので,次は kdelibs をインストールしようとすると... 途中でコンパイルがコケました.
/usr/include/X11/Xlib.h:3772: error: 'XConnectionWatchProc' has not been declared
嫌な予感がします./usr/include/X11/ の下で grep -R XConnectionWatchProc を実行しても,その定義が見当たりません.X も再インストールです.
こうなってくると,もう最初から入れ直した方が早いんじゃないだろうかと思うのですが,とりあえず作業を続行することにします.
私が作業を手抜きしようとしたがために得た今回の教訓は,「GNU Parted で ReiserFS のリサイズをするより,全てをバックアップしてパーティションを切り直した方が安全」です.
December 17, 2006
[C++] std::map::at() の代替
g++-4.1.1 付属の libstdc++ には,std::map::at() というメンバ関数がついています.これは,引数として与えたキーに対応する要素を参照するものですが,operator[] と違うのは,未登録のキーを参照しようとすると,std::out_of_range 例外が投げられるという点です.
g++-4.1.1 で開発しているときにこの関数を使用して何事もなくコンパイルできていましたが,g++-3.4.4 な環境でコンパイルしてエラーが出るので調べてみました.
その結果,g++-4.1.1 の stl_map.h:353 には次のように書いてあり,at() メンバ関数は非標準であることが判明しました.
// DR 464. Suggestion for new member functions in standard containers.
非標準のメンバ関数を使うのもいささか気がひけるので(と言いつつ,Boost は使いまくっていますが),代替の関数 Map_at() を書くことになりました.様々な型のペアに対応できるように,テンプレート関数で書くことにします.そして,最初に書いた定義は以下の通り.左端の数字は行番号です.
5 template <typename map_type>
6 map_type::mapped_type& Map_at(map_type& m, const map_type::key_type& key)
7 {
8 map_type::iterator it = m.lower_bound(key);
9 if (it == m.end() || m.key_comp()(key, (*it).first))
10 throw std::out_of_range("Map_at");
11 return (*it).second;
12 }
g++-4.1.1 でコンパイルしてみると... 以下の通りのエラーメッセージが登場.
test.cc:6: error: expected constructor, destructor, or type conversion before '&' token
テンプレート内部において,型の周りで expected 〜
なコンパイルエラーが発生する場合,経験上 typename が抜けているので,勘と試行錯誤を組み合わせて typename を補います.そしてできたのが次のコード.
5 template <typename map_type>
6 typename map_type::mapped_type& Map_at(map_type& m, const typename map_type::key_type& key)
7 {
8 typename map_type::iterator it = m.lower_bound(key);
9 if (it == m.end() || m.key_comp()(key, (*it).first))
10 throw std::out_of_range("Map_at");
11 return (*it).second;
12 }
これでめでたくコンパイルが通りました.しかし,まさか 3 箇所も typename を書き加えることになるとは.
今回の例では,C++ Labyrinth にあるような,ポインタ型のつもりで * 記号を書いているわけでもなければ,typedef しているわけでもなかったので,2 個目の typename や 8 行目の typename がなくとも,構文から map_type::key_type や map_type::iterator がそれぞれ引数もしくは変数の型だと判断してくれると期待していたのですが,どうやらこの場合も明示しないとダメみたいです.私にはまだまだ C++ の修行が足りないようです.
それはさておき,コンパイルが通ってしまえば,それを使うのは非常に楽です.以下のような感じで使用します.
std::map<int, int> map_a;
std::map<const char*, int> map_b;
map_a.insert(std::make_pair(10, 20));
map_b.insert(std::make_pair("hoge1", 10));
try
{
std::cout << Map_at(map_a, 10) << std::endl;
std::cout << Map_at(map_b, "hoge1") << std::endl;
std::cout << Map_at(map_b, "hoge2") << std::endl;
}
catch (std::out_of_range& e)
{
std::cerr << e.what() << std::endl;
}
上記コードの実行結果です.
20 10 Map_at
std::map::at() が標準になるまではこの関数を使うことにします.
December 5, 2006
[雑記] 宮崎和牛 128 グラム 11,650 円 ?
1 週間分の食材を買い出しに行ったスーパーでのできごとです.
肉コーナーにあった宮崎和牛のパックに貼ってある値札シールを見ると,何と 128 グラムで 11,650 円と書いてあるではありませんか.高っ!
一瞬,超高級肉かとも思ったのですが,周りにあった同様のパックには正しい価格 (100 グラム当たり 1200 円) のシールが貼られていたので,このパックだけ金額が間違っていると推測できます.
即座に 1 枚写真を撮ってしまいました.それが下の写真です.確かに 11650 円です.
陳列棚の蛍光灯によるフリッカーのために綺麗な写真が撮れなかったのが残念です.
December 2, 2006
[雑記] 炊飯器で豚の角煮
炊飯器で豚の角煮を作ってみました.以前に 1 回作っており,今回は 2 回目です.1 回目の角煮の話はこの hoge diary には書いていません.
では今回の作り方です.まず最初に,豚ブロック肉の脂を抜きます.今回も,第 1 回目と同様に,フライパンで表面を満遍なく 10 分間焼いて簡単に脂を出すことに.
後は,炊飯器の釜に酒 200ml と,先程焼いた肉と輪切りにした大根を入れ,炊飯器の限界水位を越えないように注意しつつ,具材が浸るまで水を注いでから,炊飯開始.
1 度目の炊飯が完了したら,別に作っておいたゆで卵と,醤油と砂糖をそれぞれ半量入れます(面倒だったので,今回は味見しながら入れることに).そして再び炊飯開始.
2 回目の炊飯が完了したら,残りの醤油と砂糖を入れて再び炊飯.
そして 3 回目の炊飯が完了したら,ちょうど Ossan が飯を炊いて来てくれたので,できたての角煮と共に飯を頂くことに.
そして 2 人は驚愕の事実に気づきます.味がまだ具材に完全に染み込んでいないことに... 肉の柔らかさに問題が無かっただけに惜しいです.ちなみに,1 回目は醤油を入れすぎて味が濃くなってしまいました.
その晩はとりあえず薄味の角煮を Ossan と 2 人で食いましたが... 許して,Ossan.
その夜,醤油を足して再び炊飯を行いました.そしてできあがったのが以下の写真に写る角煮.中央にあるのがメインの豚肉です.
次は最初から 4 回炊飯することにします.