global は危険デス

id:logion:20060209#p1 において、最初に std::locale::global(std::locale("")); を実行しておけばバッチリなんて書いていましたが、テストプログラムでの実験しかしていませんでした。実際に自作アプリに組み込んで動かしてみたら、えらい副作用があることがわかりました。
locale は文字コードだけでなく数値や日付・通貨の表記法なども司るため、std::wostringstream で数値を文字列にしている部分でことごとく 3 桁ごとにカンマを入れてくれやがります。うちのアプリの場合、こんなバグが出てしまいました。

  • テキストボックスで "21000" と入力
  • 表示の際に、"21,000" と表示される
  • カンマが数字の切れ目と判断され 21 が入力されたことになる orz

…いやまぁ文字列の読み込みに std::wistringstream を使ってなかったので、そういう対称性がないコードを書くのが悪いやん、という指摘はごもっともです。
が、数字を文字列にする時のデフォルト動作を変更されてしまうとは予想していませんでした。(数字にカンマを入れるかどうかなんて、国や言語ごとに一意に決まるもんやないと思うので、常にカンマが出るのはさすがにやりすぎちゃうんかと問いつめたい所…<誰に?)

まあ愚痴ってもどうしようもないので、locale の大部分を "C" (classic) localeにし、文字コードの部分だけ "" (システムのデフォルト) を使いたい場合は、以下のようにすればいいようです。

std::locale::global(std::locale(std::locale::classic(), "", std::locale::ctype));

ちなみに、このコードは C++Builder6J では「内部コンパイルエラー」が出てしまうあたりがとっても泣けてきます。
うぅ、C++Builder2006J ではちゃんと通るからもうえぇよ…。orz (移行の理由ができた、ということにしておこう…)