2010-11-12-01-文字コードの話 - 13
>> Site top >> weblog >> 月別アーカイブ >> 2010年11月のlog >> 2010-11-12-01-文字コードの話 - 13
最終更新日付:2010/11/12 01:00:00
文字コードの話 - 13
2010 年 11 月 12 日
実装を進めていると、デザインの段階では思いもよらなかった問題に行き当たったりする。今回は、件の反復子をポインタのように使った場合の問題について。
早速だが例から入ることにしよう。以下のコードでは、用意したバッファの先頭を指すイテレータを準備し、operator* と後置 operator++ を並用して値 0x82A0 を設定している。
char buf[64]; Encoding::SJIS::Iterator itr = sjis.GetIterator( buf ); *itr++ = 0x82A0; // どうなる?
さて、上記のコードを実行した直後の時点で、itr はどこを指しているだろうか? このイテレータが理想的な挙動を示すならば、それは buf + 2 に等しいだろう。しかし、残念ながらそうはならないのである。
ポイントは後置インクリメント演算子にある。言語仕様に沿った一般的な実装は以下のようになるだろう。
Iterator Iterator::operator++( int ) { Iterator tmp = *this; ++*this; return tmp; }
もうおわかりだろう。この場合、operator* が適用される対象は上記コードでの tmp という一時オブジェクトであり、イテレータ本体の移動は operator* の実行よりも先に行なわれるわけだ。結果として、++*this; はそれ以前に「そこにある」値に従って実行されるため、うまく行ったとしてもそれは偶然に過ぎないことになる。
この問題は後置インクリメント演算子に本質的なもので、小手先のテクニックでどうこうできるものでもなさそうだ。要素1つ(つまり1文字)あたりのバイト幅が不定である限り、*itr++ = c; という文を常に正しく処理することはできない(ように見える)。
最初は「そういうものだ」ということで諦めて放置しようかと思ったが、こういうのは忘れた頃に自分をびっくりさせる地雷に化けるものだ。そこで、後置インクリメント/デクリメント演算子自体を private 宣言にして無実装とする抑止策を取った方が賢明と判断した。
‥‥‥なんだか、まだしばらくこの話題が続きそうだ。
コメント
このページのタグ
Page tag : 開発
Copyright(C) 2005-2021 project-enigma.
Generated by CL-PREFAB.